AGC009 题解

D. Uninity

考虑这棵树形成的过程:初始都为 \(0\),每次合并时变为 \(k\) ,我们则将合并中心打上 \(k\) 的标记。结束时每个点上都有标记,这些标记有性质:对于不同的两点 \(u,v\),若 \(tag_u=tag_v\),则在 \(u,v\) 的路径上存在一点的 \(tag\) 大于它们。可以发现这也是冲要条件。

现在我们需要让最大的 \(tag\) 最小。考虑贪心地从叶子往根(随意钦定)选。记显然每个都选最小可行的可以保证正确性。记 \(s_x\) 集合表示在 \(x\) 的子树中已经存在且到 \(x\) 还没有比它大的集合。

  1. \(c\in child_x\),则 \(tag_x\notin s_c\)

  2. \(c_1,c_2\in child_x\),则 \(tag_x>\max(s_{c_1}\cap s_{c_2})\)

若不满足 \(1\),则存在其子树中一点到 \(x\) 不满足。

若不满足 \(2\),则存在两个不同子树中的点通过 \(x\) 连起来而不满足。

此时我们已经知道了 \(tag_x\),考虑由子树信息推出 \(s_x\)。我们发现所有小于 \(tag_x\) 的都可取了,所有大于 \(tag_x\) 且原来就不可取的还是不可取,且 \(tag_x\) 不可取。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int n,m,ans,lab[maxn],s[maxn];
int beg[maxn],nex[maxn],to[maxn],e;
inline void add(int x,int y){
	nex[++e]=beg[x];beg[x]=e;to[e]=y;
	nex[++e]=beg[y];beg[y]=e;to[e]=x;
}
inline void dfs(int x,int fa){
	int tt=0;
	for(int i=beg[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa)continue;
		dfs(t,x);
		tt|=s[x]&s[t];
		s[x]|=s[t];
	}
	int k=tt?32-__builtin_clz(unsigned(tt)):0;
	lab[x]=__builtin_ctz(unsigned((s[x]|((1<<k)-1))+1));
	s[x]=(s[x]>>lab[x]|1)<<lab[x];
}
int main(){
	n=read();
	for(int i=1,x,y;i<n;i++)
		x=read(),y=read(),add(x,y);
	dfs(1,0);
	for(int i=1;i<=n;i++)
		ans=max(ans,lab[i]);
	printf("%d\n",ans);
    return 0;
}

posted @ 2022-01-04 19:16  syzf2222  阅读(35)  评论(0编辑  收藏  举报