【2019 CCPC 江西省賽】Cotree 樹重心
阿新 • • 發佈:2020-10-18
題意
給出 \(n\) 個頂點,\(n-2\) 條邊。也就是兩顆樹,現在讓連一條邊,變成一顆樹,使得 \(\sum_{i=1}^{n}\sum_{j=i+1}^{n}dis(i,j)\) 最小。
瞎嗶嗶
看完題盲猜一波把兩棵樹的重心連到一起。寫起來太麻煩,而且不保證結論正不正確。
就去寫了一個等腰梯形的題目,然後由於自己把題意讀錯,瘋狂WA,最後yzj隊,把A題一過,跑我們上面去了。
一看他們過,我猜結論應該是正確的。
yzj說就剩一小時了,這題程式碼挺長的,你們應該過不了了。
一聽,這這這。
開始瘋狂敲程式碼,半小時寫完,小小的改了一下bug,過了樣例,一交過了。
真爽
題解
先求出兩顆樹的重心,連起來。
如何算這個呢?
\(\sum_{i=1}^{n}\sum_{j=i+1}^{n}dis(i,j)\)
我們列舉邊的貢獻。
對於每條邊邊它的貢獻為:\(sz[u]*(n-sz[u])\),即左右兩邊的頂點數量相乘。
程式碼
/* * @Autor: valk * @Date: 2020-08-11 12:38:37 * @LastEditTime: 2020-10-16 13:32:27 * @Description: 如果邪惡 是華麗殘酷的樂章 它的終場 我會親手寫上 晨曦的光 風乾最後一行憂傷 黑色的墨 染上安詳 */ #include <bits/stdc++.h> #define fuck system("pause") #define pb emplace_back using namespace std; typedef long long ll; typedef unsigned long long ull; const int mod = 1e9 + 7; const int seed = 12289; const double eps = 1e-6; const int inf = 0x3f3f3f3f; const int N = 1e5 + 10; int sz[N], mxsz[N]; vector<int> vec[N]; int vis[N], n, m; void solve(int u, int fa) { ++m; vis[u] = 1; for (int v : vec[u]) { if (v == fa || vis[v]) continue; solve(v, u); } } int dfs(int u, int fa) { sz[u] = 1; for (int v : vec[u]) { if (v == fa) continue; dfs(v, u); sz[u] += sz[v]; mxsz[u] = max(mxsz[u], sz[v]); } if (vis[u] == 0) mxsz[u] = max(mxsz[u], n - sz[u]); else mxsz[u] = max(mxsz[u], m - sz[u]); } int dfs1(int u, int fa) { sz[u] = 1; for (int v : vec[u]) { if (v == fa) continue; dfs1(v, u); sz[u] += sz[v]; } } ll rel = 0; int dfs2(int u, int fa) { for (int v : vec[u]) { if (v == fa) continue; rel += 1LL * sz[v] * (n - sz[v]); dfs2(v, u); } } int main() { scanf("%d", &n); for (int i = 1; i <= n - 2; i++) { int u, v; scanf("%d%d", &u, &v); vec[u].pb(v), vec[v].pb(u); } solve(1, 1); //染色 n -= m; int rt1, rt2; for (int i = 1; i <= n + m; i++) { if (vis[i] == 1) { rt1 = i; break; } } for (int i = 1; i <= n + m; i++) { if (vis[i] == 0) { rt2 = i; break; } } dfs(rt1, rt1); int minn = inf; for (int i = 1; i <= n + m; i++) { if (vis[i] == 1) minn = min(minn, mxsz[i]); } int w1, w2; for (int i = 1; i <= n + m; i++) { if (vis[i] == 1 && minn == mxsz[i]) { w1 = i; } } dfs(rt2, rt2); minn = inf; for (int i = 1; i <= n + m; i++) { if (!vis[i]) { minn = min(minn, mxsz[i]); } } for (int i = 1; i <= n + m; i++) { if (vis[i] == 0 && minn == mxsz[i]) { w2 = i; } } vec[w1].pb(w2), vec[w2].pb(w1); memset(sz, 0, sizeof(sz)); n += m; dfs1(1, 1); dfs2(1, 1); printf("%lld\n", rel); return 0; }