传送门
dsu on tree 的经典题
能组成回文串的前提是至多有一种字符是奇数个,统计同一深度下各种字符个数即可。启发式合并即可优雅的暴力统计。
ps:一直wa41,也找不到错误,看了样例才发现输入中多了一个空行,我是单个字符读入的。
又发现一个新的wa题方法。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1000010;
int n,m,a[N],b[N],c[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b)
{
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
int sz[N],son[N],dep[N];
void dfs(int u,int fa)
{
sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa) continue;
dep[v]=dep[u]+1;
dfs(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
int cnt[N][30];
vector<pair<int,int>> query[N];
bool ans[N];
int flag;
void count(int u,int fa,int val)
{
cnt[dep[u]][a[u]]+=val;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==flag||v==fa) continue;
count(v,u,val);
}
}
bool check(int dep)
{
int s=0;
for(int i=0;i<26;++i)
s+=(cnt[dep][i]&1);
return s<=1;
}
void dfs(int u,int fa,int op)
{
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==son[u]||v==fa) continue;
dfs(v,u,0);
}
if(son[u])
{
dfs(son[u],u,1);
flag=son[u];
}
count(u,fa,1);
for(int i=0;i<query[u].size();++i)
ans[query[u][i].second]=check(query[u][i].first);
flag=0;
if(!op) count(u,fa,-1);
}
char s[N];
int main()
{
memset(h,-1,sizeof h);
scanf("%d%d",&n,&m);
for(int i=2;i<=n;++i)
{
int x;
scanf("%d",&x);
add(x,i);
add(i,x);
}
scanf("%s",s+1);
//getchar();
for(int i=1;i<=n;++i)
{
// char s;
// scanf("%c",&s);
a[i]=s[i]-'a';
}
for(int i=1;i<=m;++i)
{
scanf("%d%d",b+i,c+i);
query[b[i]].push_back({c[i],i});
}
dep[1]=1;
dfs(1,-1);
dfs(1,-1,0);
for(int i=1;i<=m;++i)
printf("%s\n",ans[i]?"Yes":"No");
return 0;
}