[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爆

 

 

 

 

 

 

 

 

 

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