官方题解是离线询问,dfs树形转线性,然后二分找区间。
还有一种比较好的做法是直接dfs,将当前访问这个结点u相关的询问之前的状态存起来,然后访问完以后利用异或开关性,得到这颗子树上的答案。
代码是学习别人的http://blog.csdn.net/squee_spoon/article/details/47666667
#include<bits/stdc++.h> using namespace std; const int maxn = 5e5+5; char s[maxn]; int head[maxn],to[maxn],nxt[maxn],ecnt; void addEdge(int u,int v) { to[ecnt] = v; nxt[ecnt] = head[u]; head[u] = ecnt++; } int qhead[maxn],qnxt[maxn]; void init() { memset(head,-1,sizeof(head)); memset(qhead,-1,sizeof(qhead)); } struct Query { int h; int other; bool ans; }query[maxn]; void addQuery(int v,int i) { qnxt[i] = qhead[v]; qhead[v] = i; } bool ok(int n) { while(n){ if(n&1){ return !(n>>1); } n>>=1; } return true; } int d[maxn]; int cnt[maxn]; void dfs(int u) { for(int i = qhead[u]; ~i; i = qnxt[i]){ query[i].other = cnt[query[i].h]; } cnt[d[u]] ^= (1<<(s[u]-'a')); for(int i = head[u]; ~i; i = nxt[i]){ d[to[i]] = d[u]+1; dfs(to[i]); } for(int i = qhead[u]; ~i; i = qnxt[i]){ query[i].ans = ok(cnt[query[i].h]^query[i].other); } } int main() { init(); int n,m; scanf("%d%d",&n,&m); for(int i = 2; i <= n; i++){ int fa; scanf("%d",&fa); addEdge(fa,i); } scanf("%s",s+1); for(int i = 0; i < m; i++){ int v; scanf("%d%d",&v,&query[i].h); addQuery(v,i); } d[1] = 1; dfs(1); for(int i = 0; i < m; i++){ query[i].ans?puts("Yes"):puts("No"); } return 0; }