[ARC079D] Namori Grundy (基环树)

 

 

题解

一道基环树思维题

首先,题目给出了一棵基环外向树,求是否存在一种对节点的赋权方案

使得当前点u的权值=自己所有出点v的权值的mex

显然,无出度的点的权值必须赋为0

然后我们只需要在每一个非叶子节点取它所有儿子权值的mex就可以了

但是环上的权值怎么办呢

当环上每个点的出点的权值y不等于它的权值x时,可以保留当前的方案

如果存在一对点u->v的权值x,y相等,就还需要对点u的权值x加一,并继续调整

考虑一种极端的情况:环上所有点的权值都相等

如3   3   3   3   3   3

我们经过这样的调整之后会得到

3   4   3   4   3   4

恰好是符合条件的

但如果是3   3   3   3   3

我们将会一直这样调整下去(因为总会有两个相邻点的权值相同)

所以只有在环长为奇数且环上所有点的权值都相等的情况下,不存在这样的图

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 200005
int fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int fa[N],cir[N],clen,dep[N];bool onc[N];
void findcir(int u,int ff)
{
	fa[u]=ff;
	dep[u]=dep[ff]+1;
	for(int v,p=fir[u];p;p=nxt[p]){
		if((v=to[p])!=ff){
			if(!dep[v])findcir(v,u);
			else if(dep[v]<dep[u]){
				for(int t=u;;t=fa[t]){
					onc[t]=1;cir[++clen]=t;
					if(t==v)break;
				}
			}
		}
	}
}
int f[N];bool vis[N];
void dfs(int u,int ff)
{
	for(int v,p=fir[u];p;p=nxt[p])if((v=to[p])!=ff&&!onc[v])dfs(v,u);
	for(int v,p=fir[u];p;p=nxt[p])if((v=to[p])!=ff&&!onc[v])vis[f[v]]=1;//  KKK
	while(vis[f[u]])f[u]++;
	for(int v,p=fir[u];p;p=nxt[p])if((v=to[p])!=ff&&!onc[v])vis[f[v]]=0;
}
int main()
{
	int n=gi(),i;
	for(i=1;i<=n;i++)adde(gi(),i);
	findcir(1,0);
	for(i=1;i<=clen;i++)dfs(cir[i],0);
	bool flg=0;
	for(i=2;i<=clen;i++)
		if(f[cir[i]]!=f[cir[1]]){flg=1;break;}
	if(!flg&&(clen&1))printf("IMPOSSIBLE\n");
	else printf("POSSIBLE\n");
}

 

 

关于基环树的一点小细节

1、求完环之后不能再次使用fa来判断父亲,

因为你的初始点可能是一个非环点,这样就会造成某个子树无法被DP到

2、DP的时候先求完所有儿子的DP值再来DP当前点

否则儿子也可能会用到一些全局数组,影响当前点答案的计算

3、调用环上的点的编号是,一定要记得写cir[i],否则会WA爆

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章