【2019 CCPC 江西省赛】Cotree 树重心
题意
给出 \(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;
}