570D.Tree Requests (离线+树上启发式合并)
一棵以1为根的树,每个节点上都有1个字母,有m个询问。每次询问v对应的子树中,深度为h的这层节点的字母,能否打乱重排组成回文串。根的深度为1,每个点的深度为到根的距离。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+100;
int c[maxn];
vector<int> g[maxn];
int f[maxn];//表示当前节点的子树内,深度为i的节点状态的异或和
int L[maxn],R[maxn],id[maxn];
int dep[maxn];
int size[maxn];
int tot;
int son[maxn];
int n,m;
int ans[maxn];
vector<pair<int,int> > q[maxn];
void dfs1 (int x,int pre) {
dep[x]=dep[pre]+1;
size[x]=1;
L[x]=++tot;
id[tot]=x;
for (int y:g[x]) {
if (y==pre) continue;
dfs1(y,x);
size[x]+=size[y];
if (size[son[x]]<size[y]) son[x]=y;
}
R[x]=tot;
}
void cal (int x,int pre) {
f[dep[x]]^=c[x];
for (int y:g[x]) {
if (y==son[x]||y==pre) continue;
for (int j=L[y];j<=R[y];j++) {
int z=id[j];
f[dep[z]]^=c[z];
}
}
for (pair<int,int> y:q[x]) {
int ff=0;
if (f[y.first]==0) ff=1;
for (int i=0;i<26;i++) if (f[y.first]==(1<<i)) ff=1;
ans[y.second]=ff;
}
}
void dfs2 (int x,int pre,int kp) {
for (int y:g[x]) {
if (y==son[x]||y==pre) continue;
dfs2(y,x,0);
}
if (son[x]) {
dfs2(son[x],x,1);
}
cal(x,pre);
if (!kp) for (int i=L[x];i<=R[x];i++) f[dep[id[i]]]=0;
}
int main () {
scanf("%d%d",&n,&m);
for (int i=2;i<=n;i++) {
int x;
scanf("%d",&x);
g[x].push_back(i);
}
string s;
cin>>s;
for (int i=1;i<=n;i++) c[i]=(1<<(s[i-1]-'a'));
for (int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
q[x].push_back(make_pair(y,i));
}
dfs1(1,0);
dfs2(1,0,1);
for (int i=1;i<=m;i++) printf("%s\n",ans[i]==1?"Yes":"No");
}