AFO

CF1228F

写了一个特别麻烦的做法

首先一共有三种情况:1.删掉一个叶子,2.删掉根的一个儿子,3.其他的节点

第一种情况会有两个度数为2的节点,第二种情况没有度数为2的节点,第三种情况会有一个度数为4的节点

然后从现在开始降智..

首先求一下每个点的size,从被删除的点开始一直到根的size都会比正常情况少1,如果遇见既不是正常大小也不是正常大小-1的点直接输出0

如果大小不对的点个数不对输出0

这样就可以处理1和3.单独特判掉2就行


官方题解只要找一下直径就能盘段是不是0

有道理。。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>

using namespace std;

const int M = 1000001;
int n,m,k,a[M],s[M],N,ver[M],nex[M],head[M],cnt,dp[M],vis[M],S2,S4,x,y,d[M];
queue<int>q,rs;
void add(int x,int y)
{
	ver[++cnt]=y, nex[cnt]=head[x], head[x]=cnt;
	ver[++cnt]=x, nex[cnt]=head[y], head[y]=cnt;
}


int main()
{
	scanf("%d",&N); n=(1<<N)-1;
	if(N==2)
	{
		printf("2\n1 2");
		return 0;
	}
	for(int i=1;i<=n-2;i++)
	{
		scanf("%d%d",&x,&y);
		d[x]++, d[y]++;
		add(x,y);
	}
	for(int i=1;i<n;i++)
	{
		s[i]=1;
		if(d[i]==2) S2++;
		if(d[i]==4 && S4) { printf("0"); return 0; }
		if(d[i]==4) S4=i;
		if(d[i]>4) { printf("0"); return 0; }
	}
	if(S2==2 && S4) { printf("0"); return 0; }
	for(int i=1;i<=n-1;i++) if(d[i]==1) s[i]=1,q.push(i);
	while(q.size())
	{
		int x=q.front(); q.pop();
		 vis[x]=1;
		for(int i=head[x];i;i=nex[i])
		{
			if(vis[ver[i]]) continue;
			s[ver[i]]+=s[x]; d[ver[i]]--;
			if(d[ver[i]]==1)q.push(ver[i]);
		}
	}
	int x=0,S=0;
	for(int i=1;i<n;i++)
	{
		int k=s[i]+2,g=s[i]+1;
		if((g & -g) == g)  continue;
		if((k & -k) !=k) { printf("0"); return 0; }
		if(!x || s[i]<s[x]) x=i; 
		S++;
	}
	if(!S2)
	{
		int B=0;
		for(int i=1;i<n;i++) if(s[i]==(n-1)/2) B=i;
		if(B)
		{
			printf("2\n");
			printf("%d %d",min(x,B),max(x,B));
			return 0;
		}
	}
	int k=s[x]+2,t=-1;
	while(k) k>>=1, t++;
	if(S!=N-t+1) { printf("0"); return 0; }	
	if(x) {printf("1\n%d",x); return 0;}
	printf("2\n");
	for(int i=1;i<n;i++)
	{
		if(s[i]==(n-1)/2) printf("%d ",i);
	}
}
posted @ 2019-10-10 18:08  ZUTTER☮  阅读(135)  评论(0编辑  收藏  举报