【CSP-S2019D2T3】树的重心

Description

在这里插入图片描述
在这里插入图片描述

Solution

  • 考场上没有足够的时间,也并没有打二叉树的,所以只有55分了。。。。
  • 首先树的重心有几个性质我居然一直不知道!(虽然题面里面都有提及,但是我居然将它们忽略了)。
    1.树的重心当且仅当最大的子树大小小于n/2。如果不是的话可以通过往大于n/2的子树中调整获得更优的答案。再推一下可以发现,当这个时候的重心的最大子树的size为n/2且n为偶数的时候,这个儿子也是一个重心,因此重心只有一个或两个。
    2.树的重心一定在包括根节点的重链上。首先求重心有一种我之前一直没有用过的方法,就是从根节点往下逼近,那么如果在逼近的过程中如果往轻儿子走的话,当前最大重儿子的最小size的最大值就己经没有往重儿子走优。
    3.根据上面的两个性质,可以得知只需要找到重链上最后一个sz>=n/2的,那么在这个重链以前的都一定满足第一个条件,又因为只有一个或两个,所以取末尾两个对比一下就好哦了。
  • 可以用倍增维护重链。
  • 换根转移即可。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 300005
#define maxp 20
#define mem(a) memset(a,0,sizeof(a))
#define ll long long 
using namespace std;

int T,n,i,j,k,x,y;
int em,e[maxn*2],nx[maxn*2],ls[maxn];
int fa[maxn],sz[maxn],gs[maxn];
int Sz[maxn],Gs[maxn],f[maxn][maxp],F[maxn][maxp];
ll ans;

void read(int &x){
	x=0; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}

void insert(int x,int y){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
}

void DFS(int x,int p){
	sz[x]=1,fa[x]=p;
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p){
		DFS(e[i],x),sz[x]+=sz[e[i]];
		if (!gs[x]||sz[gs[x]]<sz[e[i]]) 	
			gs[x]=e[i];
	}
	f[x][0]=gs[x],Gs[x]=gs[x];
	for(int i=1;i<maxp;i++) f[x][i]=f[f[x][i-1]][i-1];
}

void upd(int x){
	for(int i=1;i<maxp;i++) 	
		F[x][i]=F[F[x][i-1]][i-1];
}

void Get(int st){
	int N=Sz[st];
	int y1=st,y2=st,c=0;
	for(int i=maxp-1;i>=0;i--) if (F[y1][i]&&Sz[F[y1][i]]>=(N+1)/2)
		y1=F[y1][i],c+=1<<i;
	if (c){
		c--;
		for(int i=maxp-1;i>=0;i--) if (c>=(1<<i))
			c-=1<<i,y2=F[y2][i];
		int mx=min(max(N-Sz[y1],Sz[Gs[y1]]),max(N-Sz[y2],Sz[Gs[y2]]));
		if (max(N-Sz[y1],Sz[Gs[y1]])==mx) ans+=y1;
		if (max(N-Sz[y2],Sz[Gs[y2]])==mx) ans+=y2;
	} else ans+=y1;
}

int totT,To[maxn],pre[maxn],nex[maxn];
void DFS2(int x,int p){
	if (x!=1) Get(x);
	totT=0;
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p) To[++totT]=e[i];
	int mx=To[1];
	for(int i=2;i<=totT;i++){
		pre[To[i]]=mx;
		if (Sz[To[i]]>Sz[mx]) mx=To[i];
	}
	mx=To[totT];
	for(int i=totT-1;i>=1;i--){
		nex[To[i]]=mx;
		if (Sz[To[i]]>Sz[mx]) mx=To[i];
	}
	
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p){
		Gs[x]=fa[x];
		if (pre[e[i]]&&Sz[pre[e[i]]]>Sz[Gs[x]]) Gs[x]=pre[e[i]];
		if (nex[e[i]]&&Sz[nex[e[i]]]>Sz[Gs[x]]) Gs[x]=nex[e[i]];
		F[x][0]=Gs[x],upd(x);
		Sz[x]=n-Sz[e[i]];
		Get(x);
		DFS2(e[i],x);
	}
	Sz[x]=sz[x],Gs[x]=gs[x];
	memcpy(F[x],f[x],sizeof(f[x]));
}

int main(){
	freopen("centroid.in","r",stdin);
	freopen("centroid.out","w",stdout);
	read(T);
	while (T--){
		read(n),ans=0;
		em=0,mem(ls),mem(f),mem(sz),mem(gs),mem(pre),mem(nex);
		for(i=1;i<n;i++) read(x),read(y),insert(x,y);
		DFS(1,0);
		memcpy(Sz,sz,sizeof(sz));
		memcpy(F,f,sizeof(F));
		DFS2(1,0);
		printf("%lld\n",ans);
	}
}

posted @ 2019-11-25 21:44  Deep_Thinking  阅读(229)  评论(0编辑  收藏  举报