2019 CCPC Jiangxi A. Cotree #树的重心#

Cotree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1029    Accepted Submission(s): 349

Problem Description

Avin has two trees which are not connected. He asks you to add an edge between them to make them connected while minimizing the function ∑ni=1∑nj=i+1dis(i,j), where dis(i,j) represents the number of edges of the path from i to j. He is happy with only the function value.

Input

The first line contains a number n (2<=n<=100000). In each of the following n−2 lines, there are two numbers u and v, meaning that there is an edge between u and v. The input is guaranteed to contain exactly two trees.

Output

Just print the minimum function value.

Sample Input

3 1 2

Sample Output

4

Source

Recommend

liuyiding

Solution

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> p;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
bool vis[maxn];
int ecnt, head[maxn];
int pre[maxn], rt[2];
int siz[maxn], maxp[maxn], dep[maxn];
ll res;
struct edge { int to, nxt; } e[maxn << 1];
set<int> col[maxn];

template<typename T = int>
inline const T read()
{
    T x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
    return x * f;
}

template<typename T>
inline void write(T x)
{
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

void addEdge(int u, int v)
{
    e[ecnt].to = v;
    e[ecnt].nxt = head[u];
    head[u] = ecnt++;
}

int Find(int id) { return pre[id] == id ? id : pre[id] = Find(pre[id]); }

void Union(int a, int b) { pre[Find(b)] = Find(a); }

void getRoot(int u, int f, int r)
{
    siz[u] = 1;
    maxp[u] = 0;
    for (int i = head[u]; ~i; i = e[i].nxt)
    {
        int v = e[i].to;
        if (vis[v] || v == f) continue;
        getRoot(v, u, r);
        siz[u] += siz[v];
        maxp[u] = max(maxp[u], siz[v]);
    }
    res += (ll)siz[u] * ((int)col[Find(u)].size() - siz[u]);
    maxp[u] = max(maxp[u], (int)col[Find(u)].size() - siz[u]);
    if (maxp[u] < maxp[rt[r]]) rt[r] = u;
}

void dfs(int u, int f, int sz)
{
    dep[u] = dep[f] + 1;
    res += (ll)dep[u] * sz;
    for (int i = head[u]; ~i; i = e[i].nxt)
    {
        int v = e[i].to;
        if (v == f) continue;
        dfs(v, u, sz);
    }
}

int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("input.txt", "r", stdin);
#endif
    int n = read();
    memset(head, -1, sizeof(head));
    for (int i = 1; i <= n; i++) pre[i] = i;
    for (int i = 0; i < n - 2; i++)
    {
        int u = read(), v = read();
        addEdge(u, v);
        addEdge(v, u);
        Union(u, v);
    }
    for (int i = 1; i <= n; i++) col[Find(i)].insert(i);
    maxp[0] = inf;
    getRoot(1, 0, 0); // to get rt(A)
    getRoot(rt[0], 0, 0); // res += Σdis(i, j) (i, j ∈ A)
    maxp[0] = inf;
    for (int i = 1; i <= n; i++)
    {
        if (Find(i) != Find(1))
        {
            getRoot(i, 0, 1); // to get rt(B)
            break;
        }
    }
    getRoot(rt[1], 0, 1); // res += Σdis(i, j) (i, j ∈ B)
    res >>= 1; // 之前各重复计算了一次
    dep[0] = -1;
    dfs(rt[0], 0, siz[rt[1]]); // res += siz[rt(B)] * Σdis(i, rt(A)) (i ∈ A)
    dfs(rt[1], 0, siz[rt[0]]); // res += siz[rt(A)] * Σdis(i, rt(B)) (i ∈ B)
    res += (ll)siz[rt[0]] * siz[rt[1]];
    write(res);
    putchar(10);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35850147/article/details/104300013