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;
}