Codeforces 570D(DFS序)

Codeforces 570D
题意:一棵树根为1,告诉你每个点上的字母。问$v$节点子树(包括$v$节点)在第$h$行的所有节点的字母能否组成回文串。

为什么这题卡常啊……
子树问题考虑 DFS 序,这里因为和深度有关就分层处理。每一层建 vector 存这层每个字母在 DFS 序中的位置,因为按照 DFS 序存,vector 内部有序,所以每次查询在 vector 二分一个子树区间统计个数,能否组成回文当且仅当出现奇数次字母小于等于1

知识点:
分层用 vector 处理。

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
const int MAXN = 500000 + 5;
int n, q, ll[MAXN], rr[MAXN], sz, dep[MAXN];
char s[MAXN];
vector<int> G[MAXN], whw[MAXN][30];
inline void ins(int x, int y) {
    G[x].push_back(y), G[y].push_back(x);
}
void dfs(int u, int pa) {
    dep[u] = dep[pa] + 1, sz++, ll[u] = sz;
    whw[dep[u]][s[u] - 'a'].push_back(sz);
    for (int i = 0; i < (int)G[u].size(); i++) {
        int v = G[u][i];
        if (v != pa) dfs(v, u);
    }
    rr[u] = sz;
}
void clean() {
    ms(dep, 0), sz = 0;
}
int solve() {
    clean();
    for (int p, i = 2; i <= n; i++) scanf("%d", &p), ins(i, p);
    scanf("%s", s + 1);
    dfs(1, 0);
    while (q--) {
        int u, h; scanf("%d%d", &u, &h);
        int cnt = 0;
        for (int i = 0; i < 26; i++) {
            int hh = upper_bound(whw[h][i].begin(), whw[h][i].end(), rr[u]) - upper_bound(whw[h][i].begin(), whw[h][i].end(), ll[u] - 1);
            if (hh % 2) cnt++;
            if (cnt > 1) break;
        }
        if (cnt == 1 || cnt == 0) printf("Yes\n");
        else printf("No\n");
    }
    return 0; 
}
int main() {
    scanf("%d%d", &n, &q), solve();
    return 0;
}
------ 本文结束 ------