题目大意:给出一个节点u问,节点u的子树中在深度为h的节点能不能组成一个回文串。
解题思路:寒假训练赛的一个题目,当时也不会,补题的时候用dfs序+二分写的。后来发现能用启发式合并写。
当时二分差点挂了,果然树上启发式合并跑的飞快。。。。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define N 500005
#define mp(x,y) make_pair(x,y)
typedef pair<int,int>pii;
vector<pair<int,int>>V[N];
vector<int>G[N];
char s[N];
int sz[N],son[N];
int s1[N],dep[N];
int cnt[N][26];
int Son;
int ans[N];
void dfs1(int u,int de)
{
sz[u]=1;
dep[u]=de;
int mx=-1;
for(auto v:G[u]){
dfs1(v,de+1);
sz[u]+=sz[v];
if(sz[v]>mx)mx=sz[v],son[u]=v;
}
}
void add(int u,int val)
{
cnt[dep[u]][s1[u]]+=val;
for(auto v:G[u]){
if(v!=Son){
add(v,val);
}
}
}
void dfs(int u,int f)
{
for(auto i:G[u]){
if(i==son[u])continue;
dfs(i,0);
}
if(son[u])dfs(son[u],1),Son=son[u];
add(u,1);
for(auto i:V[u])
{
int tmp=0,flag=0;
for(int j=1;j<=26;j++)
{
if(cnt[i.first][j]&1)
{
tmp++;
}
if(tmp>=2)
{
ans[i.second]=0;
flag=1;
}
}
if(!flag)ans[i.second]=1;
}
if(son[u])Son=0;
if(!f)add(u,-1);
}
int main()
{
int n,m;
sca(n),sca(m);
for(int i=2;i<=n;i++)
{
int tmp;
sca(tmp);
G[tmp].pb(i);
}
scanf("%s",s+1);
rep(i,1,n)s1[i]=s[i]-'a'+1;
dfs1(1,1);
for(int i=1;i<=m;i++)
{
int x,h;
sca(x),sca(h);
V[x].pb(mp(h,i));
}
dfs(1,1);
rep(i,1,m)puts(ans[i]?"Yes":"No");
}