【JZOJ6435】【luoguP5666】【CSP-S2019】樹的重心

description


analysis

  • 需要知道一棵樹的重心一定在從根出發的重鏈上,可以考慮先進行樹鏈剖分弄出重兒子和次重兒子,再倍增維護重兒子

  • 由於重鏈上有一個或兩個重心,接下來求的重心都是深度較大的,只需判斷其父節點是否也滿足重心的性質即可

  • 現在要斷掉一條邊(x,y)(x,y),假設xxyy的父親,需要分別求出yy的子樹的重心、以及除了yy的子樹以外的樹的重心

  • 倍增數組已經維護好了所以yy的重心很好求,對於視作xx爲根的子樹則需要重新維護一次倍增數組

  • yy是重兒子則用次重兒子與xx父親sizesize比較,否則用原來的重兒子比;知道了重兒子則可以重新算倍增數組

  • 然後把xx設爲yy的兒子,其實就是換根操作,遞歸下去求解,回溯時重新再算xx的倍增數組;時間複雜度O(nlogn)O(n\log n)


code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define MAXN 300005
#define MAXM MAXN*2
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=las[a];i;i=nex[i])

using namespace std;

ll las[MAXM],nex[MAXM],tov[MAXM];
ll fa[MAXN],size[MAXN],tsize[MAXN],hson[MAXN],secson[MAXN];
ll son[MAXN][20];
ll n,T,tot,ans,log2n;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline ll max(ll x,ll y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline void link(ll x,ll y){nex[++tot]=las[x],las[x]=tot,tov[tot]=y;}

inline void dfs1(ll x,ll y)
{
	size[x]=1,fa[x]=y;
	rep(i,x)if (tov[i]!=y)
	{
		dfs1(tov[i],x),size[x]+=size[tov[i]];
		if (size[tov[i]]>size[hson[x]])secson[x]=hson[x],hson[x]=tov[i];
		else if (size[tov[i]]>size[secson[x]])secson[x]=tov[i];
	}
	tsize[x]=size[x],son[x][0]=hson[x];
}
inline void dfs2(ll x,ll y)
{
	rep(i,x)if (tov[i]!=y)
	{
		if (tov[i]==hson[x])son[x][0]=secson[x];
		else son[x][0]=hson[x];
		if (size[y]>size[son[x][0]])son[x][0]=y;
		fo(k,1,log2n)son[x][k]=son[son[x][k-1]][k-1];

		size[x]=n-tsize[tov[i]],size[tov[i]]=tsize[tov[i]],fa[x]=fa[tov[i]]=0;

		ll now=x;
		fd(k,log2n,0)if (son[now][k] && size[x]-size[son[now][k]]<=size[x]/2)now=son[now][k];
		if (max(size[son[now][0]],size[x]-size[now])<=size[x]/2)ans+=now;
		if (max(size[son[fa[now]][0]],size[x]-size[fa[now]])<=size[x]/2)ans+=fa[now];

		now=tov[i];
		fd(k,log2n,0)if (son[now][k] && size[tov[i]]-size[son[now][k]]<=size[tov[i]]/2)now=son[now][k];
		if (max(size[son[now][0]],size[tov[i]]-size[now])<=size[tov[i]]/2)ans+=now;
		if (max(size[son[fa[now]][0]],size[tov[i]]-size[fa[now]])<=size[tov[i]]/2)ans+=fa[now];

		fa[x]=tov[i],dfs2(tov[i],x);
	}
	fa[x]=y,son[x][0]=hson[x],size[x]=tsize[x];
	fo(k,1,log2n)son[x][k]=son[son[x][k-1]][k-1];
}
int main()
{
	T=read();
	while (T--)
	{
		memset(las,0,sizeof(las)),memset(nex,0,sizeof(nex));
		memset(tov,0,sizeof(tov)),memset(secson,0,sizeof(secson));
		memset(fa,0,sizeof(fa)),memset(son,0,sizeof(son)),memset(hson,0,sizeof(hson));
		n=read(),log2n=(ll)log2(n),ans=tot=0;
		fo(i,1,n-1){ll x=read(),y=read();link(x,y),link(y,x);}
		dfs1(1,0);
		fo(j,1,log2n)fo(i,1,n)son[i][j]=son[son[i][j-1]][j-1];
		dfs2(1,0),printf("%lld\n",ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章