题目链接:luogu.com.cn/problem/CF570D
题目大意:
图片说明

思路:轻重链启发式合并,cut[i][j]:维护深度为i的j单词个数。如果查询时,有<=1的单词个数为奇数就可以组成回文串。

 #include <bits/stdc++.h>
using namespace std;

char s[500005], c[500005];
vector<int> G[500005];
vector<pair<int, int> > q[500005];
int siz[500005], son[500005], dfn[500005], pos[500005], d[500005], cut[500005][26], T=0;
//pos:dfs序为i的节点
//c:i节点的词
int ans[500005];
void dfs(int u, int fa, int deep){
    siz[u]=1; dfn[u]=++T, pos[T]=u; d[u]=deep;
    for(auto x: G[u]){
        if(x!=fa){
            dfs(x, u, deep+1);
            siz[u]+=siz[x];
            son[u]=siz[x]>siz[son[u]]?x:son[u];
        }
    }
}

void DFS(int u, int fa, int k){
    for(auto x: G[u]){
        if(x!=fa&&x!=son[u]){
            DFS(x, u, 0);
        }
    }
    if(son[u]) DFS(son[u], u, 1);
    for(auto x: G[u]){
        if(x!=fa&&x!=son[u]){
            for(int i=0; i<siz[x]; i++){
                int nowson=pos[dfn[x]+i];
                cut[d[nowson]][c[dfn[nowson]]]++;
            }
        }
    }
    cut[d[u]][c[dfn[u]]]++;
    for(auto x: q[u]){
        int s=0;
        int deep=x.first;
        for(int i=0; i<26; i++){
            if(cut[deep][i]%2){
                s++;
            }
        }
        if(s<=1){
            ans[x.second]=1;
        }
    }
    if(!k){
        for(int i=0; i<siz[u]; i++){
            int nowson=pos[dfn[u]+i];
            for(int k=0; k<26; k++){
                cut[d[nowson]][k]=0;
            }
        }
    }
}

int main(){
    int n, m, x, y; scanf("%d%d", &n, &m);
    for(int i=2; i<=n; i++){
        scanf("%d", &x);
        G[x].push_back(i);
        G[i].push_back(x);
    }
    dfs(1, 0, 1);
    scanf("%s", s+1);
    for(int i=1; i<=n; i++){
        c[dfn[i]]=s[i]-'a';
    }
    for(int i=1; i<=m; i++){
        scanf("%d%d", &x, &y);
        q[x].push_back({y, i});
    }
    DFS(1, 0, 0);
    for(int i=1; i<=m; i++){
        if(ans[i]) printf("Yes\n");
        else printf("No\n");
    }
}