树的重心

求重心的本质,其实就是枚举每一个节点的所有子树,使得该节点中的最大子树最小化

#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
int e[N],h[N],ne[N],mds[N],ds[N],rt,idx,n;
// mds代表所有子树中最大的子树,ds代表所有子树的总和,rt代表重心
void add(int a,int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}
void dfs(int u,int fa) {
    mds[u] = 0;
    ds[u] = 1;
    for(int i = h[u]; ~i;i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        dfs(j,u);
        ds[u] += ds[j];// 算出所有子树的总和
        mds[u] = max(mds[u],ds[j]);// 求出所有子树中最大的子树
    }
    mds[u] = max(mds[u], n - ds[u]);// 把父节点也看作一颗子树
    if(rt == 0 || mds[u] < mds[rt]) rt = u;
    if(mds[u] == mds[rt] && u < rt) rt = u;// 取编号较小的一个点
}
int main() {
    int t;
    cin >> t;
    while(t --) {
        memset(mds,0,sizeof mds);
        memset(ds,0,sizeof ds);
        memset(h,-1,sizeof h);
        rt = idx = 0;
        cin >> n;
        for(int i = 0;i < n - 1; ++i) {
            int a,b;
            cin >> a >> b;
            add(a,b);
            add(b,a);
        }
        dfs(1,0);
        cout << rt <<' ' << mds[rt] << endl;
    }
    return 0;
}

模板题

Balancing Act

posted @ 2020-06-21 11:33  南风--  阅读(83)  评论(0编辑  收藏  举报