https://nanti.jisuanke.com/t/A1267
艹,忘记矩阵乘法不支持交换律了,调了一年。
我们把询问放到询问路径的端点上,然后在点分治的过程中,看不同子树中有没有同一条询问路径的端点,有的话就匹配成功计算出答案。
由于矩阵乘法不支持交换律,所以第i条询问路径的起点u添加i,终点v添加i+q,而且在点分治dfs的过程中,要维护从rt到v的disdw[v],也要维护反向的disup[v],然后再匹配成功的时候判断一下乘的顺序
由于是64位的01矩阵,所以用ull对矩阵进行压位,最后复杂度是nlogn*64*64的,跑了3s,本题时限9s,还算好
似乎还可以直接dfs,然后用带权并查集维护矩阵乘积,少个log
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int maxn=6e3+10;
const int maxl=3e4+10;
const int mod=19260817;
int n,q,cnt,len,top,tlen;
ull sed;
int ehead[maxl],a[maxl],s[maxl],tmp[maxl],ans[maxl],numid[maxl];
int mi19[65],mi26[65];
struct ed
{
int to,nxt;
}e[maxl<<1];
bool vis[maxl];
struct matrix
{
ull a[64];
matrix()
{
memset(a,0,sizeof(a));
}
inline void clear()
{
memset(a,0,sizeof(a));
}
inline void init()
{
for(int i=0;i<64;i++)
a[i]=(1ull<<i);
}
matrix operator * (const matrix &b)const
{
matrix c;
for(int i=0;i<64;i++)
for(int j=0;j<64;j++)
if((a[i]>>j)&1)
c.a[i]^=b.a[j];
return c;
}
}m[maxn],num[maxl],disup[maxn],disdw[maxn],one;
struct centertree
{
int n,ans,mi;
int son[maxl];
inline void dfs(int u,int fa)
{
son[u]=1;int v,mx=0;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(vis[v] || v==fa) continue;
dfs(v,u);
son[u]+=son[v];
mx=max(mx,son[v]);
}
mx=max(mx,n-son[u]);
if(mx<mi)
mi=mx,ans=u;
}
inline int getcenter(int u)
{
ans=0;mi=maxl;
dfs(u,0);
return ans;
}
}tree;
set <int> qry[maxl];
inline void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void init()
{
for(int i=1;i<=n;i++)
{
m[i].clear();
for(int p=0;p<64;p++)
{
sed ^=sed * sed +15;
for(int q=0;q<64;q++)
m[i].a[p]|=sed&(1ull<<q);
}
}
}
inline int trans(matrix x)
{
int sum=0;
for(int i=1;i<=64;i++)
for(int j=1;j<=64;j++)
if(x.a[i-1]&(1ull<<(j-1)))
sum=(sum+1ll*mi19[i]*mi26[j]%mod)%mod;
return sum;
}
inline void prework()
{
for(int i=1;i<=n;i++)
{
ehead[i]=0,vis[i]=false;
qry[i].clear();
}
cnt=0;int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
scanf("%llu",&sed);
init();
for(int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
if(u==v)
{
ans[i]=trans(m[u]);
continue;
}
qry[u].insert(i);qry[v].insert(i+q);
}
}
inline void dfs(int u,int fa)
{
s[++top]=u;int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(vis[v] || v==fa) continue;
disdw[v]=disdw[u]*m[v];
disup[v]=m[v]*disup[u];
dfs(v,u);
}
}
inline int opp(int d)
{
return d>q ? d-q: d;
}
inline void calc(int u,int fa)
{
top=0;disdw[u]=m[u];disup[u]=m[u];
dfs(u,0);int x;
for(int i=1;i<=top;i++)
{
tlen=0;
for(int d : qry[s[i]])
if(numid[opp(d)])
{
if(d>q)
ans[opp(d)]=trans(num[opp(d)]*m[fa]*disdw[s[i]]);
else
ans[opp(d)]=trans(disup[s[i]]*m[fa]*num[opp(d)]);
tmp[++tlen]=d;
x= (d<=q) ? d+q:d-q;
qry[numid[opp(d)]].erase(qry[numid[opp(d)]].find(x));
}
for(int j=1;j<=tlen;j++)
qry[s[i]].erase(qry[s[i]].find(tmp[j]));
}
for(int i=1;i<=top;i++)
for(int d : qry[s[i]])
{
numid[opp(d)]=s[i];
if(d>q)
num[opp(d)]=disdw[s[i]];
else
num[opp(d)]=disup[s[i]];
a[++len]=opp(d);
}
}
inline void solv(int u)
{
vis[u]=true;int v,rt;
len=0;
for(int d : qry[u])
numid[opp(d)]=u,a[++len]=opp(d),num[opp(d)]=one;
disdw[u]=disup[u]=one;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(vis[v]) continue;
calc(v,u);
}
for(int i=1;i<=len;i++)
numid[opp(a[i])]=0;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(vis[v]) continue;
tree.n=tree.son[v];
rt=tree.getcenter(v);
solv(rt);
}
}
inline void mainwork()
{
tree.n=n;
int rt=tree.getcenter(1);
solv(rt);
}
inline void print()
{
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
}
int main()
{
//freopen("out.out","w",stdout);
one.init();
mi19[0]=1;mi26[0]=1;
for(int i=1;i<=64;i++)
{
mi19[i]=1ll*mi19[i-1]*19%mod;
mi26[i]=1ll*mi26[i-1]*26%mod;
}
while(~scanf("%d%d",&n,&q))
{
prework();
mainwork();
print();
}
return 0;
}