CSP2019樹的重心

2022-05-11 00:45:11 字數 1589 閱讀 1010

題解:csp2019d2t3

首先我們要明確乙個性質,那就是對於一棵樹的任何乙個節點來說,如果這個點不是重心,那麼這棵樹的重心就一定在這個節點的以重兒子為根節點的子樹裡

證明顯而易見,因為該點不是重心所以siz[重兒子]一定大於$\lfloor \frac \rfloor$

另外還有乙個重心的定義:重心所有子樹的大小一定小於等於$\lfloor \frac \rfloor$

我們首先遍歷整棵樹,切斷一條邊(u,v)後,我們得到以u為根、以v為根的兩顆樹

然後不斷向重兒子跳,直到找到重心

這裡我們可以用倍增實現,時間複雜度$o(n log_ n)$

我們預處理倍增陣列fv[x][i],然後對於以v為根的子樹,直接倍增找重兒子即可

對於以u為根的子樹,也可以用類似的方法解決,我們只需要讓u的父親變成u的兒子,即f[fa]=u,hv[u][0]=siz[hv[u][0]]

其實這個題還蠻難的 

code:

#include#include

#include

#include

#include

#include

#define rep(i,a,b) for(int i=a;i<=b;i++)

#define dwn(i,a,b) for(int i=a;i>=b;i--)

#define maxn 300004

using

namespace

std;

typedef

long

long

ll;ll ans;

int t,n,tot,nxt[maxn<<1],to[maxn<<1],fir[maxn],hv[maxn][20

],f[maxn],siz[maxn],shv[maxn],thv[maxn],tsiz[maxn],s;

intread()

while('0'

<=ch && ch<='9')

return x*f;

}void ade(int x,int

y)void dfs1(int x,int

fa) hv[x][

0]=thv[x]; siz[x]=tsiz[x];

}void

init()

bool chk(int x,int

y)void recalc(int

x) void

clear()

void dfs2(int x,int

y) siz[x]=tsiz[x]; hv[x][0]=thv[x]; f[x]=y;

recalc(x);

}int

main()

dfs1(

1,0);

init();

s=tsiz[1

]; dfs2(

1,0);

printf(

"%lld\n

",ans);

}return0;

}

CSP2019 樹的重心

點這裡看題目。原來資料的奇怪結尾就可以拿來判斷特徵呀 太簡單就不說了。考慮完全二叉樹怎麼做。這裡需要注意一點,就是 n 262143 2 1 也就是說,資料實際上就是一棵滿二叉樹。由於滿二叉樹具有極強的對稱性,我們不難想到這樣解決 首先,答案一定包含 frac rt 其中 rt 是樹的根。考慮根的左...

CSP2019 樹的重心 解題報告

csp2019 樹的重心 t 組資料 1 le t le 5 每次給定一棵 n 個點的樹 1 le n le 299995 設 e 為樹的邊集,v x,v y 分別為刪去邊 x,y 後 點 x 所在的點集和點 y 所在的點集.求 sum left sum x 是 v x 的重心 x sum y 是 ...

CSP2019 樹的重心(樹的重心 倍增 換根)

當年我做這道題時還太嫩了,只能想到暴力。其實如果會了更高的科技這道題只要稍微對暴力優化一下就能ac 我也不會含淚75pts了 廢話不說了,暴力的思路就是列舉每一條邊然後求兩個子樹的重心。直接求重心的複雜度是 o n 的,我們考慮優化到 o log 我們想要求以 x 為根的子樹的重心,首先有個引理 這...