題目連接:https://codeforces.com/problemset/problem/570/Dc++
題解:數組
這種題,基本上容易想到DFS序。spa
而後,咱們若是再把全部節點分層存下來,那麼顯然能夠根據 $in[v],out[v]$ 在層內二分出一段屬於 $v$ 的子樹的節點。code
那麼咱們進一步考慮,若是把一層的節點,按 $a \sim z$ 再分開來,用一個 $S[c][d]$ 數組來存全部字母爲 $c$,深度爲 $d$ 的節點的 $in[]$ 值。blog
這樣一來,對於一個詢問 $v,h$,就在 $S[c][h]$ 二分找到屬於區間 $[in[v],out[v]]$ 的那一段,這一段的長度若是爲 $r$,說明 $v$ 節點的子樹中、深度爲 $h$ 的、字母爲 $c$ 的節點有 $r$ 個,get
這個 $r$ 若爲偶數,那麼必然能夠用來組成迴文串;若是爲奇數,那麼最多隻能一個字母的個數是奇數,不然就不能組成迴文串了。it
AC代碼:class
#include<bits/stdc++.h> #define pb(x) push_back(x) using namespace std; typedef pair<int,int> P; #define fi first #define se second const int maxn=5e5+10; int n,m; char c[maxn]; int d[maxn]; vector<int> G[maxn]; vector<int> S[26][maxn]; int clk; int maxd; int in[maxn],out[maxn]; void dfs(int x,int depth) { in[x]=++clk; maxd=max(maxd,depth); S[c[x]-'a'][d[x]=depth].pb(in[x]); for(auto y:G[x]) dfs(y,depth+1); out[x]=clk; } int main() { scanf("%d%d",&n,&m); for(int y=2,x;y<=n;y++) { scanf("%d",&x); G[x].pb(y); } scanf("%s",c+1); clk=0, maxd=0, dfs(1,1); while(m--) { int v,h; scanf("%d%d",&v,&h); if(d[v]>=h) { printf("Yes\n"); continue; } int cnt=0; for(int i=0;i<26;i++) { int L=lower_bound(S[i][h].begin(),S[i][h].end(),in[v])-S[i][h].begin(); int R=upper_bound(S[i][h].begin(),S[i][h].end(),out[v])-S[i][h].begin(); cnt+=(R-L)%2; } if(cnt>1) printf("No\n"); else printf("Yes\n"); } }