Tree Requests
经典的树上启发式合并题目了(其实就是瞎暴力)。
对于一颗有根树,我们先做一次dfs找到每个节点的重儿子,然后在答案统计的时候优先遍历轻儿子,不保留答案,最后遍历重儿子保留答案。
这颗树显然我们要维护的信息就是每一层字母的奇偶性,所以我们直接在每一层开一个30大小的bitset。
然后暴力遍历,暴力合并即可。
/* Author : lifehappy */ #include <bits/stdc++.h> using namespace std; const int N = 5e5 + 10; int head[N], to[N], nex[N], cnt = 1; int l[N], r[N], rk[N], dep[N], son[N], sz[N], ans[N], tot, n, m; char str[N]; void add(int x, int y) { to[cnt] = y; nex[cnt] = head[x]; head[x] = cnt++; } void dfs(int rt, int fa) { dep[rt] = dep[fa] + 1, sz[rt] = 1; l[rt] = ++tot, rk[tot] = rt; for(int i = head[rt]; i; i = nex[i]) { if(to[i] == fa) continue; dfs(to[i], rt); if(!son[rt] || sz[to[i]] > sz[son[rt]]) son[rt] = to[i]; sz[rt] += sz[to[i]]; } r[rt] = tot; } bitset<30> num[N]; typedef pair<int, int> pii; vector<pii> ask[N]; void dfs(int rt, int fa, int keep) { for(int i = head[rt]; i; i = nex[i]) { if(to[i] == fa || to[i] == son[rt]) continue; dfs(to[i], rt, 0); } if(son[rt]) dfs(son[rt], rt, 1); for(int i = head[rt]; i; i = nex[i]) { if(to[i] == fa || to[i] == son[rt]) continue; for(int j = l[to[i]]; j <= r[to[i]]; j++) { int now = str[rk[j]] - 'a'; if(num[dep[rk[j]]][now]) num[dep[rk[j]]][now] = 0; else num[dep[rk[j]]][now] = 1; } } int now = str[rt] - 'a'; if(num[dep[rt]][now]) num[dep[rt]][now] = 0; else num[dep[rt]][now] = 1; for(auto i : ask[rt]) { if(num[i.first].count() > 1) { ans[i.second] = 0; } else { ans[i.second] = 1; } } if(!keep) { for(int i = l[rt]; i <= r[rt]; i++) { int now = str[rk[i]] - 'a'; num[dep[rk[i]]][now] = 0; } } } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); scanf("%d %d", &n, &m); for(int i = 2; i <= n; i++) { int x; scanf("%d", &x); add(x, i); } scanf("%s", str + 1); for(int i = 1; i <= m; i++) { int rt, h; scanf("%d %d", &rt, &h); ask[rt].push_back(make_pair(h, i)); } dfs(1, 0); dfs(1, 0, 1); for(int i = 1; i <= m; i++) { puts(ans[i] ? "Yes" : "No"); } return 0; }