又是莫名RE系列…
首先一个想法,就是把字母转化成一个二进制位,因为如果一个字符出现两次,那么它们就可以被配成一对,也就是说,这两个就和没有是一样的.
那这对我们有什么帮助呢?
那就和异或一样了,两个状态合并的同时,相同为0,不同为1,这样的话,最后合并出来的状态里有的二进制1的数量必定不大于1,这样的状态才可能被变成回文串.
所以加入和删除都是异或操作.
接下来就是怎么知道一棵子树下面的某一行的异或值和了.
参考这里,我们可以有一种方法来完成这个.
先把每个节点的重儿子找到,然后先去递归解决轻儿子,最后解决重儿子,但是把重儿子的值留下来,因为现在这个节点也会用到这个重儿子里面的所有信息,所以现在并不用删除.
然后计算这个节点的时候把所有的都加上去,最后出递归的时候再看一下它是不是重儿子,如果不是的话就把以它为根的这棵子树上的节点都去掉.
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#define M 1000005
using namespace std;
void Rd(int &res){
res=0;char p;
while(p=getchar(),p<'0');
do{
res=(res<<1)+(res<<3)+(p^48);
}while(p=getchar(),p>='0');
}
struct W{
int to,nx;
}Lis[M];
int Head[M],tot=0;
void Add(int x,int y){
Lis[tot].to=y,Lis[tot].nx=Head[x],Head[x]=tot++;
}
struct T{
int id,hi,nx;
}Q[M];
int rHead[M],rtot=0;
void rAdd(int x,int id,int hi){
Q[rtot].id=id,Q[rtot].hi=hi,Q[rtot].nx=rHead[x],rHead[x]=rtot++;
}
char S[M];
bool ans[M],bigson[M];
int de[M],bin[32],cntson[M],Mxson[M];
int pl[M];
set<int>st;
void Init(int x){
cntson[x]=1;
Mxson[x]=0;
int Mx=0;
for(int i=Head[x],to;~i&&(to=Lis[i].to,1);i=Lis[i].nx){
Init(to),cntson[x]+=cntson[to];
if(cntson[to]>Mx)Mx=cntson[to],Mxson[x]=to;
}
}
void add_ph(int x){
pl[de[x]]^=bin[S[x]-'a'];
for(int i=Head[x],to;~i&&(to=Lis[i].to,1);i=Lis[i].nx)
if(!bigson[to])add_ph(to);
}
void dfs(int x,bool kep){
for(int i=Head[x],to;~i&&(to=Lis[i].to,1);i=Lis[i].nx)
if(to!=Mxson[x])dfs(to,0);
if(Mxson[x]!=0)dfs(Mxson[x],1),bigson[Mxson[x]]=1;
add_ph(x);
for(int i=rHead[x],id,hi;~i&&(id=Q[i].id,hi=Q[i].hi,1);i=Q[i].nx)
ans[id]=(st.find(pl[hi])!=st.end());
if(Mxson[x]!=0)bigson[Mxson[x]]=0;
if(!kep)add_ph(x);
}
int main(){
memset(Head,-1,sizeof(Head));
memset(rHead,-1,sizeof(rHead));
for(int i=0;i<31;i++)bin[i]=(1<<i);
for(int i=0;i<26;i++)st.insert(1<<i);st.insert(0);
int n,m;Rd(n),Rd(m);
de[1]=1;
for(int i=2,x;i<=n;i++)Rd(x),Add(x,i),de[i]=de[x]+1;
scanf("%s",S+1);
for(int i=1,x,y;i<=m;i++)Rd(x),Rd(y),rAdd(x,i,y);
Init(1);
dfs(1,1);
for(int i=1;i<=m;i++)
if(ans[i])puts("Yes");
else puts("No");
return 0;
}