蒟蒻第一次写树分块,成功趋势。最后三个点TLE了,有没有大佬帮忙看一下。
#include<bits/stdc++.h>
using namespace std;
const int N=4e4+10;
int n,m,a[N],ans=0;
int b[N];
int block=0;
int f[N][30],deep[N],Size[N],maxdeep[N];//maxdeep[i]记录i属于的深度为deep[x]~deep[x]+block的块中的最大深度
int id[N],tot=0;//id标记关键点
int s[N],ff[N],top=0;//s[i]一条到根的路径上的关键点,ff[i]表示这一条路径上离关键点i最近的祖先关键点
bitset<N> bt[50][50],record;//维护颜色的出现种类
int head[N*2],cnt=0;
struct node{
int v,nex;
}e[N*2];
void add(int u,int v){
e[++cnt].v=v;
e[cnt].nex=head[u];
head[u]=cnt;
}
void dfs1(int u,int fa){
f[u][0]=fa;
deep[u]=deep[fa]+1;
maxdeep[u]=deep[u];
Size[u]=1;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa) continue;
dfs1(v,u);
Size[u]+=Size[v];
maxdeep[u]=max(maxdeep[u],maxdeep[v]);
}
//每次选择一个深度最大的非关键点,若它的1~block级祖先都不是关键点,则我们把它的block级祖先标记为关键点
if(maxdeep[u]-deep[u]>=block){
id[u]=++tot;
maxdeep[u]=deep[u];//注意改变当前的maxdeep
}
}
void dfs2(int u,int fa){
//考虑一条到根的路径上的所有关键点,用bitset维护它们两两间出现的颜色
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa) continue;
if(id[v]){
int last=id[s[top]],now=id[v];
for(int x=v;x!=s[top];x=f[x][0]){
bt[last][now].set(a[x]);//将bitset中第a[x]位变成1
}
for(int j=1;j<top;j++){
bt[id[s[j]]][now]=bt[id[s[j]]][last]|bt[last][now];
}
ff[v]=s[top];
s[++top]=v;
}
dfs2(v,u);
if(id[v]) top--;//注意是一条到根的路径,需要清除
}
}
int lca(int x,int y){
if(deep[x]<deep[y]) swap(x,y);
for(int i=25;i>=0;i--){
if(deep[f[x][i]]>=deep[y]){
x=f[x][i];
}
}
if(x==y) return x;
for(int i=25;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
block=1000;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
int p=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+p+1,a[i])-b;
}
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,0);
for(int j=1;j<=25;j++){
for(int i=1;i<=n;i++){
f[i][j]=f[f[i][j-1]][j-1];
}
}
if(!id[1]) id[1]=++tot;
s[++top]=1;
dfs2(1,0);
while(m--){
int u,v;
cin>>u>>v;
u^=ans;
record.reset();//清空record
int k=lca(u,v);
while(u!=k&&!id[u]){
record.set(a[u]);
u=f[u][0];
}
while(v!=k&&!id[v]){
record.set(a[v]);
v=f[v][0];
}
if(u!=k){
int uu=u;
while(deep[ff[u]]>=deep[k]) uu=ff[uu];
if(uu!=u) record|=bt[id[uu]][id[u]];
while(uu!=k){
record.set(a[uu]);
uu=f[uu][0];
}
}
if(v!=k){
int vv=v;
while(deep[ff[v]]>=deep[k]) vv=ff[vv];
if(vv!=v) record|=bt[id[vv]][id[v]];
while(vv!=k){
record.set(a[vv]);
vv=f[vv][0];
}
}
record.set(a[k]);
ans=record.count();
cout<<ans<<endl;
}
return 0;
}