题目链接:https://codeforces.com/contest/570/problem/D
题意:n条边,m个询问,每个节点上都有一个字符(仅为小写英文字符)。根为1。每个询问由v和h组成,问v的子树中,深度为h的节点任意排列是否能组成回文字符串(空字符串也是),每个询问输出“Yes”或“No”。
思路:维护每个深度中每个字符的个数,最多只能有一个字符的个数为奇数。给每个询问建图,把每个询问归到相应v的子树中即可。
代码:
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
using namespace std;
const int N = 5e5+10;
int n,m;
char s[N];
struct edge{
int to,nex;
}g[N];
int head[N],cnt;
struct node{
int id,dep,nex;
}q[N];
int head1[N],cnt1;
int sz[N],dep[N],son[N];
void getsz(int u){
sz[u]=1;
int mx=-1;
for(int i=head[u];i!=-1;i=g[i].nex){
int v=g[i].to;
dep[v]=dep[u]+1;
getsz(v);
if(mx<sz[v]){
mx=sz[v];
son[u]=v;
}
sz[u]+=sz[v];
}
}
int num[N][30],SON;
void dfs1(int u,int x){
num[dep[u]][s[u]-'a']+=x;
for(int i=head[u];i!=-1;i=g[i].nex){
int v=g[i].to;
if(v==SON) continue;
dfs1(v,x);
}
}
bool ans[N];
void dfs(int u,bool keep){
for(int i=head[u];i!=-1;i=g[i].nex){
int v=g[i].to;
if(v==son[u]) continue;
dfs(v,0);
}
if(son[u]!=-1){
dfs(son[u],1);
SON=son[u];
}
dfs1(u,1);
SON=0;
for(int i=head1[u];~i;i=q[i].nex){
int deep=q[i].dep;
int nu=0;
for(int j=0;j<26;j++)
if(num[deep][j]&1) nu++;
ans[q[i].id]=(nu<=1);
}
if(keep==0)
dfs1(u,-1);
}
void add(int u,int v){
g[cnt]=edge{v,head[u]};
head[u]=cnt++;
}
void add1(int u,int id,int de){
q[cnt1]=node{id,de,head1[u]};
head1[u]=cnt1++;
}
int main(void){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
son[i]=head[i]=head1[i]=-1;
for(int i=2;i<=n;i++){
int u;
scanf("%d",&u);
add(u,i);
}
scanf("%s",s+1);
for(int i=1;i<=m;i++){
int u,d;
scanf("%d%d",&u,&d);
add1(u,i,d);
}
dep[1]=1;
getsz(1);
dfs(1,0);
for(int i=1;i<=m;i++)
puts(ans[i]?"Yes":"No");
return 0;
}