题目链接:luogu.com.cn/problem/CF570D
题目大意:
思路:轻重链启发式合并,cut[i][j]:维护深度为i的j单词个数。如果查询时,有<=1的单词个数为奇数就可以组成回文串。
#include <bits/stdc++.h>
using namespace std;
char s[500005], c[500005];
vector<int> G[500005];
vector<pair<int, int> > q[500005];
int siz[500005], son[500005], dfn[500005], pos[500005], d[500005], cut[500005][26], T=0;
//pos:dfs序为i的节点
//c:i节点的词
int ans[500005];
void dfs(int u, int fa, int deep){
siz[u]=1; dfn[u]=++T, pos[T]=u; d[u]=deep;
for(auto x: G[u]){
if(x!=fa){
dfs(x, u, deep+1);
siz[u]+=siz[x];
son[u]=siz[x]>siz[son[u]]?x:son[u];
}
}
}
void DFS(int u, int fa, int k){
for(auto x: G[u]){
if(x!=fa&&x!=son[u]){
DFS(x, u, 0);
}
}
if(son[u]) DFS(son[u], u, 1);
for(auto x: G[u]){
if(x!=fa&&x!=son[u]){
for(int i=0; i<siz[x]; i++){
int nowson=pos[dfn[x]+i];
cut[d[nowson]][c[dfn[nowson]]]++;
}
}
}
cut[d[u]][c[dfn[u]]]++;
for(auto x: q[u]){
int s=0;
int deep=x.first;
for(int i=0; i<26; i++){
if(cut[deep][i]%2){
s++;
}
}
if(s<=1){
ans[x.second]=1;
}
}
if(!k){
for(int i=0; i<siz[u]; i++){
int nowson=pos[dfn[u]+i];
for(int k=0; k<26; k++){
cut[d[nowson]][k]=0;
}
}
}
}
int main(){
int n, m, x, y; scanf("%d%d", &n, &m);
for(int i=2; i<=n; i++){
scanf("%d", &x);
G[x].push_back(i);
G[i].push_back(x);
}
dfs(1, 0, 1);
scanf("%s", s+1);
for(int i=1; i<=n; i++){
c[dfn[i]]=s[i]-'a';
}
for(int i=1; i<=m; i++){
scanf("%d%d", &x, &y);
q[x].push_back({y, i});
}
DFS(1, 0, 0);
for(int i=1; i<=m; i++){
if(ans[i]) printf("Yes\n");
else printf("No\n");
}
}
京公网安备 11010502036488号