RT,有小数据更好。
思路:深度相同时 bfs 序是连续的,同时区间的 dfs 序满足在查询的子树内,直接查找字母数量判断。如果思路错了也可以告诉我为什么。谢谢。
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
string color;
long long n,m,bfn[500010],bfn_rep[500010],dfn[500010],dfn_rep[500010],cnt_bfn,cnt_dfn,dep[500010],dep_left[500010],dep_right[500010],siz[500010];
struct segtree
{
long long sum[500010],type;
void build()
{
for(long long i=1;i<=n;i++) sum[i]=sum[i-1]+(color[bfn_rep[i]]-'a'==type);
}
long long query(long long x,long long y)
{
return sum[y]-sum[x-1];
}
}tree[26];
vector<long long>graph[500010];
void bfs()
{
queue<pair<long long,long long>>q;
q.push(make_pair(1,1));
while(!q.empty())
{
long long from=q.front().first,now_dep=q.front().second;
q.pop();
bfn[from]=++cnt_bfn;
bfn_rep[cnt_bfn]=from;
dep_left[now_dep]=dep_left[now_dep]==0?bfn[from]:dep_left[now_dep];
dep_right[now_dep]=bfn[from];
dep[from]=now_dep;
for(long long to:graph[from])
q.push(make_pair(to,now_dep+1));
}
}
void dfs(long long now)
{
dfn[now]=++cnt_dfn;
dfn_rep[cnt_dfn]=now;
siz[now]=1;
for(long long to:graph[now])
{
dfs(to);
siz[now]+=siz[to];
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(long long i=2;i<=n;i++)
{
long long fa;
cin>>fa;
graph[fa].push_back(i);
}
cin>>color;
color.insert(color.begin(),'0');
bfs();
dfs(1);
for(long long i=0;i<26;i++)
{
tree[i].type=i;
tree[i].build();
}
for(long long i=1;i<=m;i++)
{
long long u,h;
cin>>u>>h;
if(dep[u]>h)
{
cout<<"Yes\n";
continue;
}
long long l=dep_left[h],r=dep_right[h],x=0,y=0;
while(l<=r)
{
long long mid=(l+r)>>1;
if(dfn[bfn_rep[mid]]>=dfn[u])
{
x=mid;
r=mid-1;
}
else l=mid+1;
}
l=x,r=dep_right[h];
while(l<=r)
{
long long mid=(l+r)>>1;
if(dfn[bfn_rep[mid]]<=dfn[u]+siz[u]-1)
{
y=mid;
l=mid+1;
}
else r=mid-1;
}
long long len=y-x+1,sum_odd=0;
for(long long j=0;j<26;j++)
{
long long tmp=tree[j].query(x,y);
if(tmp%2) sum_odd+=tmp;
}
if(x==0||y==0) cout<<"Yes\n";
else if((len%2==0&&sum_odd>0)||(len%2==1&&sum_odd!=1)) cout<<"No\n";
else cout<<"Yes\n";
}
}