CF 570D(dsu on tree)

題目

n個以1爲根的樹,每個節點上有一個字母,m次詢問,問以x爲根的子樹中深度爲y的節點,用這些節點上的字母來組成一個單詞,假如這個字母可以是迴文串,則輸出Yes,否則輸出No

題解

用二進制數存儲x節點子樹中單詞的奇偶,奇爲1,偶爲0,這是一個26位的二進制數,只要這個二進制數爲0或者只有一位爲1,那就可以形成迴文串
其他的就是dsu on tree 的方法,先dfs一遍,建立每個節點的深度,再dfs一遍,非重兒子計算過後,將二進制數數組刪除,重兒子就相反,保存數組

代碼

#include<iostream>
#include<vector>
#define ll long long
using namespace std;
const int maxn=6e5+10;
int a[maxn],son[maxn],sz[maxn],head[maxn],dep[maxn],vis[maxn],ans[maxn],cnt;
int h[maxn];
struct E
{
	int to,nxt;
}edge[maxn];
vector<pair<int,int>> que[maxn];
void add_edge(int x,int y)
{
	edge[++cnt].nxt=head[x];
	edge[cnt].to=y;
	head[x]=cnt;
}
bool judge(int m)
{
	if(m==0) return 1;
	else{
		for(int i=0;i<26;i++){
			if(m==(1<<i)) return 1;
		}
		return 0;
	}
}
void dfs(int x,int f)
{
	dep[x]=dep[f]+1;sz[x]=sz[f]+1;
	for(int i=head[x];i;i=edge[i].nxt){
		int v=edge[i].to;
		dfs(v,x);
		sz[x]+=sz[v];
		if(!son[x]||sz[v]>sz[son[x]]) son[x]=v;
	}
}
void cal(int x)
{
	h[dep[x]]^=(1<<a[x]);
	for(int i=head[x];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(!vis[v]) cal(v);
	}
}
void dsu(int x,int p)
{
	for(int i=head[x];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v!=son[x]) dsu(v,0);
	}
	if(son[x]) dsu(son[x],1),vis[son[x]]=1;
	cal(x);
	for(auto i:que[x]){
		ans[i.first]=judge(h[i.second]);
	}
	if(son[x]) vis[son[x]]=0;
	if(!p) cal(x);
}
int main()
{
	int n,m,x,y;
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;i++){
		scanf("%d",&x);
		add_edge(x,i);
	}
	char s[maxn];
	scanf("%s", s + 1);
    for (int i = 1; i <= n; i++) a[i] = s[i] - 'a';
    pair<int,int> A;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		A.first=i;A.second=y;
		que[x].push_back(A);
	}
	dfs(1,0);
	dsu(1,0);
	for(int i=1;i<=m;i++){
		if(ans[i]){
			printf("Yes\n");
		}
		else{
			printf("No\n");
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章