• 【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
    ", rel);
        return 0;
    }
    
  • 相关阅读:
    配置OSPF负载分担
    IPv4静态路由与NQA联动
    静态路由实现路由负载分担
    静态路由实现主备备份
    (一)非整数幂情形下的广义牛顿二项式定理
    小小知识点(二十三)被科研人员忽略的ORCID —— 如何注册和使用?意义何在?
    小小知识点(二十二)word 排版技巧大全
    小小知识点(二十一)Mathtype怎么批量更改全文的公式格式
    小小知识点(十九)如何破解安装编辑PDF文本的软件——福昕编辑器和Adobe acrobat DC
    (三十二)5G前传、中传和回传
  • 原文地址:https://www.cnblogs.com/valk3/p/13828883.html
Copyright © 2020-2023  润新知