【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;
}
posted @ 2020-10-16 21:33  Valk3  阅读(83)  评论(0编辑  收藏  举报