题面

原题链接

大秦 为你打开 题目传送门

题目翻译

给定一个以 $1$ 为根的 $n$ 个结点的树,每个点上有一个字母(a-z),每个点的深度定义为该节点到 $1$ 号结点路径上的点数。每次询问 $a, b$ 查询以 $a$ 为根的子树内深度为 $b$ 的结点上的字母重新排列之后是否能构成回文串。

思路

首先这道题目一眼就是树上启发式合并,我们大力统计每一个点以及他们的子树里面每个深度每种字母有多少就可以了。代码并没有什么细节敲板子即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// #pragma GCC optimize(2)
// #pragma GCC optimize(3, "Ofast", "inline")
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef __int128 int128;
typedef pair<int , int > pii;
typedef unsigned long long ull;

namespace FastIO
{
// char buf[1 << 20], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
template<typename T> inline T read(T& x) {
x = 0;
int f = 1;
char ch;
while (!isdigit(ch = getchar())) if (ch == '-') f = -1;
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x *= f;
return x;
}
template<typename T, typename... Args> inline void read(T& x, Args &...x_) {
read(x);
read(x_...);
return;
}
inline ll read() {
ll x;
read(x);
return x;
}
};
using namespace FastIO;

const int N = 5e5 + 10;

template<int N, int M>
class Graph {
private :
struct Edge {
int to, nt, wt;
Edge() {}
Edge(int to, int nt, int wt) : to(to), nt(nt), wt(wt) {}
}e[M];
int hd[N], cnte;
public :
inline void AddEdge(int u, int v, int w = 0) {
e[++cnte] = Edge(v, hd[u], w);
hd[u] = cnte;
}
inline int head(int u) { return hd[u]; }
inline int nt(int u) { return e[u].nt; }
inline int to(int u) { return e[u].to; }
inline int wt(int u) { return e[u].wt; }
};

int n, m;
Graph< N , N > G;
char ch[N];
struct Qiz {
int h, id;
Qiz() {}
Qiz(int h, int id) : h(h), id(id) {}
};
vector<Qiz >qs[N];

inline void Input() {
read(n, m);
int x;
for(int i = 2; i <= n; i++) {
read(x);
G.AddEdge(x, i);
}
scanf("%s", ch + 1);
int v, h;
for(int i = 1; i <= m; i++) {
read(v, h);
qs[v].push_back(Qiz(h, i));
}
}

int sz[N], sn[N], dep[N];
int cnt[N][26];
bool ans[N], vis[N];

inline void Dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
sz[u] = 1;
for(int i = G.head(u); i; i = G.nt(i)) {
int v = G.to(i);
if(v == fa) continue;
Dfs(v, u);
sz[u] += sz[v];
if(sz[v] > sz[sn[u]]) sn[u] = v;
}
}

inline void Insert(int u, int fa, int f) {
if(f == 1) cnt[dep[u]][ch[u] - 'a']++;
else cnt[dep[u]][ch[u] - 'a'] = 0;
for(int i = G.head(u); i; i = G.nt(i)) {
int v = G.to(i);
if(v == fa || vis[v]) continue;
Insert(v, u, f);
}
}

inline bool Check(int d) {
int ans = 0;
for(int i = 0; i < 26; i++) {
ans += (cnt[d][i] & 1);
}
return ans <= 1;
}

inline void Dfs2(int u, int fa, int flag) {
for(int i = G.head(u); i; i = G.nt(i)) {
int v = G.to(i);
if(v == fa || v == sn[u]) continue;
Dfs2(v, u, 0);
}
if(sn[u]) Dfs2(sn[u], u, 1), vis[sn[u]] = 1;
Insert(u, fa, 1);
if(sn[u]) vis[sn[u]] = 0;
for(auto &p : qs[u]) {
ans[p.id] = Check(p.h);
}
if(!flag) Insert(u, fa, -1);
}

inline void Work() {
Dfs(1, 0); Dfs2(1, 0, 0);
for(int i = 1; i <= m; i++) {
if(ans[i]) printf("YES\n");
else printf("NO\n");
}
}

int main() {
int T = 1;
while(T--) {
Input();
Work();
}
return 0;
}