題解: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 為根的子樹的重心,首先有個引理 這...