CSP2019 樹的重心

2022-06-04 11:03:12 字數 2687 閱讀 7690

點這裡看題目。

原來資料的奇怪結尾就可以拿來判斷特徵呀

太簡單就不說了。

考慮完全二叉樹怎麼做。

這裡需要注意一點,就是:\(n=262143=2^-1\) ,也就是說,資料實際上就是一棵滿二叉樹

由於滿二叉樹具有極強的對稱性,我們不難想到這樣解決:

首先,答案一定包含 \(\frac-rt\),其中 \(rt\) 是樹的根。

考慮根的左子樹上深度為 \(d\) (根的深度為 \(0\) )的節點,我們可以任選乙個,計算出拆掉它和它父親之間的邊後,父親那顆子樹的貢獻\(t\)。那麼答案就應該加上 \(2^\times t\) 。右子樹同理。

這樣計算就是 \(o(n\log_2n)\) 的。

這個部分還可以推出通項公式。該方法的依據是:

1 . 每個點拆掉了它和它父親之後,它就是自己那部分的重心。

2 . 拆掉左邊的任何邊,根的右兒子一定是重心;拆掉右邊,左兒子一定是重心。

3 . 拆掉乙個葉子和它父親連的邊,根一定是重心。

然後就可以利用上述依據 \(o(n)\) 計算答案了。

為了方便,以下設 \(siz_u\) 表示 \(u\) 的子樹的大小。

首先我們需要非常重要的一點:

對於在乙個大小為 \(n\) 的樹上的點 \(u\) ,若 \(n-siz_u\le \lfloor\frac n 2\rfloor\) ,且它不是重心,那麼重心一定在 \(u\) 的重子樹內。

看起來很好理解吧?考慮簡單地說明一下。

假如 \(u\) 有 \(k\) 個重兒子,那麼每個重兒子的 \(siz\le \frac k\le \lfloor\frac n 2\rfloor\) 。那麼 \(u\) 就是重心,與假設不符,因而 \(u\) 只有乙個重兒子。

同理可以說明, \(u\) 的重兒子的大小 \(>\lfloor\frac n 2\rfloor\) 。也即是說,對於 \(u\) 的非重兒子 \(v\) ,一定有 \(siz_v<\lfloor\frac n 2\rfloor\rightarrow n - siz_v>\lfloor\frac n 2\rfloor\) 。所以重心一定在 \(u\) 的重兒子裡面。

看看我們得到了什麼?

如果 \(u\) 滿足 \(n - siz_u\le \lfloor \frac n 2\rfloor\) ,那麼:

1 .\(u\) 只有乙個重兒子

2 .要麼 \(u\) 是重心,要麼重心在 \(u\) 的重子樹里

3 . 如果 \(u\) 是滿足性質的最深的點那麼 \(u\) 就是重心,且 \(u\) 的父親可能是重心

第三條可以結合第二條推出。

也就是說:第

一、二條告訴了我們重心的明確方向,第三條告訴了我們重心的判斷標準,並且它還存在單調性

那我們可以幹什麼了?

倍!增!呀!

以上三條直接教會我們,只要我們能處理出 \(u\) 的朝向重兒子的倍增陣列,我們就可以快速地從樹根開始求重心。

這樣我們就可以在知道倍增陣列後 \(o(\log_2n)\) 地求出重心。那麼我們只需要列舉每一條邊,維護倍增陣列並計算重心即可。由於邊原本可能是無序的,因而我們需要進行 dfs ,並中途維護資訊(本質上還是在 「 換根 」 ),然後就可以倍增出重心了。

時間複雜度是 \(o(n\log_2n)\) 。

int p[maxn], pos[maxn];

int head[maxn], deg[maxn];

void dfs( const int u, const int fa )

}int main()

ll ans = 1ll * n * ( n + 1 ) / 2 - p[1];

ans += 1ll * n / 2 * ( p[2] + p[3] );

ans += 1ll * ( n / 2 + 1 ) * p[1];

//...

}

typedef long long ll;

const int maxn = 3e5 + 5, maxlog = 20;

template_t max( const _t a, const _t b )

int jump[maxn][maxlog];

int hs[maxn], phs[maxn], fath[maxn], siz[maxn];

ll ans;

void addedge( const int from, const int to )

void init( const int u )

void dfs( const int u, const int fa )

jump[u][0] = hs[u];

init( u );

}bool chk( const int u, const int all )

void calc( const int u, const int fa )

}void init()

int main()

CSP2019樹的重心

題解 csp2019d2t3 首先我們要明確乙個性質,那就是對於一棵樹的任何乙個節點來說,如果這個點不是重心,那麼這棵樹的重心就一定在這個節點的以重兒子為根節點的子樹裡 證明顯而易見,因為該點不是重心所以siz 重兒子 一定大於 lfloor frac rfloor 另外還有乙個重心的定義 重心所有...

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