DSU on tree确实很厉害,然后这变成了一道裸题(逃
还是稍微说一下流程吧,虽然我那个模板汇总里写过
DSU on tree可以以$O(nlog n)$的复杂度解决树上子树统计问题,它这样工作:
前置工作:对树进行轻重链剖分
1.递归求解所有的轻儿子,在回溯时消去影响
2.递归进入重儿子,在回溯时不消去影响
3.暴力统计子树信息
4.回答询问并回溯
根据轻重链剖分的性质,复杂度$O(nlog n)$
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=500005; 7 vector<pair<int,int> > qry[N]; 8 int siz[N],dep[N],imp[N],sta[N],vis[N],outp[N]; 9 int p[N],noww[2*N],goal[2*N]; 10 int n,m,t1,t2,rd,cnt; 11 char str[N]; 12 void Link(int f,int t) 13 { 14 noww[++cnt]=p[f]; 15 goal[cnt]=t,p[f]=cnt; 16 noww[++cnt]=p[t]; 17 goal[cnt]=f,p[t]=cnt; 18 } 19 int Bitcount(int s) 20 { 21 int ret=0; 22 while(s) 23 ret++,s-=s&-s; 24 return ret; 25 } 26 void DFS(int nde,int fth,int dth) 27 { 28 int tmp=0; 29 siz[nde]=1,dep[nde]=dth; 30 for(int i=p[nde];i;i=noww[i]) 31 if(goal[i]!=fth) 32 { 33 DFS(goal[i],nde,dth+1); 34 siz[nde]+=siz[goal[i]]; 35 if(siz[goal[i]]>tmp) 36 tmp=siz[goal[i]],imp[nde]=goal[i]; 37 } 38 } 39 void Count(int nde,int fth) 40 { 41 sta[dep[nde]]^=1<<(str[nde]-'a'); 42 for(int i=p[nde];i;i=noww[i]) 43 if(goal[i]!=fth&&!vis[goal[i]]) 44 Count(goal[i],nde); 45 } 46 void Getans(int nde,int fth,int hvy) 47 { 48 for(int i=p[nde];i;i=noww[i]) 49 if(goal[i]!=fth&&goal[i]!=imp[nde]) 50 Getans(goal[i],nde,0); 51 if(imp[nde]) 52 Getans(imp[nde],nde,1),vis[imp[nde]]=true; 53 Count(nde,fth); 54 vector<pair<int,int> >::iterator it; 55 for(it=qry[nde].begin();it!=qry[nde].end();it++) 56 { 57 int dth=it->second; 58 outp[it->first]=(Bitcount(sta[dth])<=1); 59 } 60 if(imp[nde]) vis[imp[nde]]=false; 61 if(!hvy) Count(nde,fth); 62 } 63 int main() 64 { 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<n;i++) 67 scanf("%d",&t1),Link(t1,i+1); 68 scanf("%s",str+1); 69 for(int i=1;i<=m;i++) 70 { 71 scanf("%d%d",&t1,&t2); 72 qry[t1].push_back(make_pair(i,t2)); 73 } 74 DFS(1,0,1),Getans(1,0,0); 75 for(int i=1;i<=m;i++) 76 outp[i]?puts("Yes"):puts("No"); 77 return 0; 78 }