CF1182D Complete Mirror

好题!!!

题目翻译

给定一个\(n\)个节点的无根树,求一个树根 \(root\) ,使得对于树中的两个节点 \(a,b\) ,若满足\(dis(a,root)=dis(b,root)\)

则必有 \(dgr_{a}=dgr_{b}\) ,无解则输出\(-1\)

\(dgr\)表示与这个点直接连边的点的个数,也就是度数

题解

首先最暴力的方法肯定就是每个节点做一次根, \(O(n)check\) 一下, \(OI\) 赛制的话会有部分分,但CF上肯定没用

首先有一个很显然的结论,如果根节点的度数 \(>=2\) 那么也就是说它每个子树都是长得一模一样的,显然它就是树的重心

那么可以先找到树的重心然后 \(check\) 一次,合法就输出

然后考虑一下根节点度数为1的时候,那么假设你从这个根\(x\)开始走,走到第一个度数>2的地方 \(y\)

根据上述提到的性质以及树的重心的性质, \(y\) 的子树的重心是 \(y\) ,那么整棵树的重心肯定在 \(x\)\(y\) 的那条链上

假如从你的那个重心连接的只有一条链,那么找到那个端点 \(check\) 一下就好了

假如不止一条,那么最多只能有两种长度不同的链,并且其中一种的出现次数必须要为 \(1\) 才可能有合法的答案,

所以你只需要找到两种不同长度的链每个端点 \(check\) 一次就好了,记录一下出现了几种就行,两种之后直接 \(break\)

由于最多只会 \(check\) 3次所以复杂度 \(O(n)\)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e5+5;
struct edge{int to,nxt;}e[maxn<<1];int rt2,len_rt2,n;
int head[maxn],dep[maxn],num,rt,son[maxn],sze,krt,siz[maxn],mx=1000000,du[maxn];
inline void add(int x,int y)
{
	e[++num]=(edge){y,head[x]};head[x]=num;du[x]++;
	e[++num]=(edge){x,head[y]};head[y]=num;du[y]++;
}
inline void getrt(int x,int f)
{
	siz[x]=1;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==f) continue;
		getrt(y,x);siz[x]+=siz[y];
		son[x]=max(son[x],siz[y]);
	}
	son[x]=max(son[x],sze-siz[x]);
	if(son[x]<mx) rt=x,mx=son[x];
}
inline void getdis(int x,int f)
{
	dep[x]=dep[f]+1;
	for(int i=head[x];i;i=e[i].nxt)
	if(e[i].to!=f) getdis(e[i].to,x);
}
vector<int>vec[maxn];
inline bool check(int x)
{
	getdis(x,0);
	for(int i=1;i<=n;i++) vec[i].clear();
	for(int i=1;i<=n;i++) vec[dep[i]].push_back(i);
	for(int i=1;i<=n;i++) for(auto x:vec[i])
	if(du[x]!=du[vec[i][0]]) return 0;
	printf("%d\n",x);exit(0);
}
inline int getline(int x,int f)
{
	if(du[x]>2) return 0;
	if(du[x]==1) {krt=x;return 1;}
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==f) continue;
		int res=getline(y,x);
		if(!res) return 0;
		else return res+1;
	}
	return 1;
}
signed main()
{
	n=read();
	for(int i=1;i<n;i++)add(read(),read());
	sze=n;getrt(1,0);check(rt);
	for(int i=head[rt];i;i=e[i].nxt)
	{
		int y=e[i].to;
		int len=getline(y,rt);
		if(!len) continue;
		if(rt2&&len!=len_rt2){check(krt);break;}
		if(!rt2){rt2=krt,len_rt2=len;check(krt);}
	}
	puts("-1");	
}
posted on 2021-11-09 21:11  JYFHYX  阅读(48)  评论(0编辑  收藏  举报