题目大意:判断v的子树中所有深度为h的点能否组成一个回文串,每个点上有一个小写字符。
题解:dsu on the tree
将字符压成二进制位,记录每个深度的点的异或值。判断异或值是不是0或者2^x。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1000003
using namespace std;
int tot,n,m,cnt,q[N],nxt[N],point[N],v[N],val[N],son[N];
int deep[N],size[N],mp[N],c[N],mark[N],ans[N],num[N];
int head[N],u[N],next[N],id[N];
char s[N];
void add(int x,int y)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void build(int x,int y,int i)
{
tot++; next[tot]=head[x]; head[x]=tot; u[tot]=y; id[tot]=i;
}
void solve(int x,int fa)
{
deep[x]=deep[fa]+1; size[x]=1;
for (int i=point[x];i;i=nxt[i]){
if (v[i]==fa) continue;
solve(v[i],x);
size[x]+=size[v[i]];
if(size[son[x]]<size[v[i]]) son[x]=v[i];
}
}
void change(int x,int fa,int vl)
{
mp[deep[x]]^=val[x]; num[deep[x]]+=vl;
for (int i=point[x];i;i=nxt[i])
if (!mark[v[i]]&&v[i]!=fa) change(v[i],x,vl);
}
void dfs(int x,int fa,bool k)
{
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa&&v[i]!=son[x]) dfs(v[i],x,0);
if (son[x]) dfs(son[x],x,1),mark[son[x]]=1;
change(x,fa,1);
for (int i=head[x];i;i=next[i])
{
int t=mp[u[i]];
if (t==0) ans[id[i]]=1;
for (int j=0;j<26;j++)
if (!(t^(1<<j))) ans[id[i]]=1;
}
if(son[x]) mark[son[x]]=0;
if (!k) change(x,fa,-1);
}
int main()
{
freopen("a.in","r",stdin);
// freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=2;i<=n;i++) {
int x; scanf("%d",&x);
add(i,x);
}
scanf("%s",s+1);
for (int i=1;i<=n;i++) val[i]=(1<<(s[i]-'a'));
memset(c,-1,sizeof(c)); tot=0;
for (int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
build(x,y,i);
}
solve(1,0);
dfs(1,0,0);
for (int i=1;i<=m;i++)
if (ans[i]) printf("Yes\n");
else printf("No\n");
}