题目大意:
就是给你一颗树,树上每个点都有一个小写字母,现在给你 m ∈ [ 1 , 5 e 5 ] m\in [1,5e5] m∈[1,5e5]次询问,每次询问给你一个u,和deep,问你在u这课子树中,距离1号节点(即根节点)为deep的全部节点是否可以组合成一个回文字符串,如果可以输出Yes,否则输出No。
解题思路:
1.首先我们知道对于这种题常规讨论就是异或,因为字母只有26个,每个看成一个二进制位,如果所在层所有节点异或和为0或者 2 i 2^i 2i那么这一层就是可以组成一个回文串。
2.首先这道题还要特判两种情况就是deep不够u的深度或者deep超过这个颗子树的最大深度,那么就是空串它也是回文的
3.对于由于是询问子树问题,我们考虑一下树上启发式合并,对于每个深度我们设置一个异或和的数组,我们如何判断这个数是否是 2 i 2^i 2i的数呢,那么就用lowbit,我们知道lowbit返回的最后一位1的位置,如果减了是0,那么就是 2 i 2^i 2i次方。
4.对于每个子树合并答案的时候我们要把询问存下来,去枚举询问,不能枚举深度,那样会TLE.
5.剩下的都是树上启发式合并的常规操作
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int maxn = 1e6 + 10;
map<PII,int> ans;
vector<int> G[maxn];
vector<int> q[maxn];
char node[maxn];
int n, m;
int depth[maxn], siz[maxn], son[maxn];
int max_dep[maxn], f[maxn];
PII ask[maxn];
void find_son(int u, int fa) {
son[u] = 0;
siz[u] = 1;
depth[u] = depth[fa] + 1;
max_dep[u] = depth[u];
f[u] = fa;
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(it == fa) continue;
find_son(it,u);
max_dep[u] = max(max_dep[u],max_dep[it]);
siz[u] = siz[it] + siz[u];
if(siz[son[u]] < siz[it])
son[u] = it;
}
}
int flag;
int Xor[maxn];
void dfs1(int u, int fa) {
Xor[depth[u]] ^= 1ll << (node[u] - 'a');
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(it == fa || it == flag) continue;
dfs1(it,u);
}
}
void dfs(int u, int fa, int keep) {
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(it == fa || it == son[u]) continue;
dfs(it,u,0);
}
if(son[u]) {
dfs(son[u],u,1);
flag = son[u];
}
dfs1(u,fa);
for(int i = 0; i < q[u].size(); ++ i) {//处理询问
int it = q[u][i];
ans[{u,it}] = (Xor[it] - (Xor[it] & -Xor[it]) == 0);
}
flag = 0;
if(!keep) {
for(int i = depth[u]; i <= max_dep[u]; ++ i) Xor[i] = 0;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
//............................
cin >> n >> m;
for(int i = 2; i <= n; ++ i) {
int x;
cin >> x;
G[x].push_back(i);
G[i].push_back(x);
}
cin >> node + 1;
find_son(1,0);
for(int i = 1; i <= m; ++ i) {
int l, r;
cin >> l >> r;
ask[i] = {l,r};
if(depth[l] > r || r > max_dep[l]) ans[{l,r}] = true;//特判
else q[l].push_back(r);//存储询问
}
dfs(1,0,0);
for(int i = 1; i <= m; ++ i)
ans[ask[i]] ? puts("Yes") : puts("No");
return 0;
}