Description
给定一棵有根树,每个结点有一个字母,每个点的深度定义为到 (1) 号点的路径上的点的个数,每次询问 (a,b),查询以 (a) 为根的子树内深度为 (b) 的结点上的字母重新排列之后能否构成回文串。
Solution
条件等价于奇数结点个数不大于 (1)
离线处理,将询问挂在 (a) 上
对于每个子树,我们需要求的是子树内各个颜色结点的个数和
由于起作用的只有奇偶性,我们可以用一个 01 串记录状态,加减就是异或
考虑按 DFS 序做差,我们只需要在进入子树的时候记录一下状态,退出的时候将当前状态与记录异或一下即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n,m,col[N],dep[N],ans[N],t1,t2;
bitset<26> s[N],rec[N];
vector <int> g[N];
struct request
{
int a,b,id;
};
vector <request> r[N];
void print()
{
cout<<" BEGIN"<<endl;
for(int i=1;i<=3;i++)
{
cout<<" "<<s[i]<<endl;
}
cout<<" END"<<endl;
}
void dfs(int p)
{
//cout<<"> "<<p<<endl;
//print();
for(auto req:r[p])
{
int id=req.id;
rec[id]=s[req.b];
}
s[dep[p]].flip(col[p]);
for(int q:g[p])
{
dep[q]=dep[p]+1;
dfs(q);
}
for(auto req:r[p])
{
int id=req.id;
bitset<26> tmp=rec[id]^s[req.b];
if(tmp.count()<=1) ans[id]=1;
}
//print();
//cout<<"< "<<p<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<n;i++)
{
cin>>t1;
g[t1].push_back(i+1);
}
for(int i=1;i<=n;i++)
{
char c;
cin>>c;
col[i]=c-'a';
}
for(int i=1;i<=m;i++)
{
cin>>t1>>t2;
r[t1].push_back({t1,t2,i});
}
dep[1]=1;
dfs(1);
for(int i=1;i<=m;i++)
{
if(ans[i]) puts("Yes");
else puts("No");
}
}