思路:
1.要能形成回文串,所以最多只能有一种字母的出现次数为奇数
2.用一个数组存每个深度每个字母出现的次数
3.查询以 为根的子树内深度为 的节点上的字母重新排列之后是否能构成回文串只要另外判断深度为的节点上是否只有一种字母的出现次数为奇数
4.为了方便离线查询,用容器存每次查询,存节点是第次询问以及查询的深度的
复杂度:
复杂度证明:
1.一个点只有在它到根节点的路径上遇到一条轻边的时候,自己的信息才会被祖先节点暴力统计一遍
2.而根据树链剖分相关理论,每个点到根的路径上有 条轻边和 条重链
3.即一个点的信息只会上传次
4.如果一个点的信息修改是 的,那么总复杂度就是的
MyCode:
#include<bits/stdc++.h> using namespace std; const int maxn=5e5+7,maxm=5e5+7; typedef long long ll; inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int head[maxn],Next[maxm],to[maxm],tot; void add(int x,int y) { to[++tot]=y; Next[tot]=head[x]; head[x]=tot; } int size[maxn],son[maxn],dep[maxn]; int cnt[maxn][30]; bool vis[maxn],ans[maxn]; #define x first #define y second vector<pair<int,int> >query[maxn]; char val[maxn]; void dfs1(int x,int f) { size[x]=1; dep[x]=dep[f]+1; for(int i=head[x],v;i;i=Next[i]) { v=to[i]; dfs1(v,x); size[x]+=size[v]; if(size[son[x]]<size[v]) son[x]=v; } } void calc(int x) { cnt[dep[x]][val[x]-'a']+=1; for(int i=head[x],v;i;i=Next[i]) { v=to[i]; if(vis[v]) continue; calc(v); } } bool check(int a[]) { int sum=0; for(int i=0;i<26;++i) if(a[i]&1) ++sum; return sum<=1; } void delet(int x) { cnt[dep[x]][val[x]-'a']-=1; for(int i=head[x],v;i;i=Next[i]) { v=to[i]; delet(v); } } void dfs2(int x,bool opt) { for(int i=head[x],v;i;i=Next[i]) { v=to[i]; if(son[x]==v) continue; dfs2(v,false); } if(son[x]) { dfs2(son[x],true); vis[son[x]]=true; } calc(x); int size=query[x].size(); if(size) { for(int i=0;i<size;++i) ans[query[x][i].x]=check(cnt[query[x][i].y]); } if(son[x]) vis[son[x]]=false; if(!opt) delet(x); } int main() { int n=read(),m=read(); for(int i=2,u;i<=n;++i) { u=read(); add(u,i); } for(int i=1;i<=n;++i) scanf(" %c",&val[i]); for(int i=1,a,b;i<=m;++i) { a=read(),b=read(); query[a].push_back(make_pair(i,b)); } dfs1(1,0); dfs2(1,false); for(int i=1;i<=m;++i) { if(ans[i]) puts("Yes"); else puts("No"); } return 0; }