【图论】树的直径

const int MAXN = 2e5 + 10;
vector<int> G[MAXN];
int dis[MAXN], mxdis;

void dfs(int u, int p) {
    dis[u] = dis[p] + 1;
    if(dis[u] > dis[mxdis])
        mxdis = u;
    for(int v : G[u]) {
        if(v == p)
            continue;
        dfs(v, u);
    }
}

int getDiameter(int root = 1) {
    mxdis = 0;
    dfs(root, 0);
    root = mxdis;
    mxdis = 0;
    dfs(root, 0);
    return dis[mxdis];
}

树的直径中心

这个直径中心和重心不一样,重心是要让每个子树的size尽可能平均,直径中心是让深度尽可能平均。不过其实用起来估计是差不多的。

下面的方法展示的就是把一棵树,最高级的中心设为A,低一级的中心设为B。虽然复杂度是错的,层数也远远不止log层,但是其实hack掉的数据还是不太好被出题人想到的。(其实是一堆长度递增的链竖着吊下来,然后横着头和头接在一起,每次让直径都没有减少,所以直径有多大就会遍历多少层,估计是要遍历根号n次?)谨慎使用!

下面的layer的最大值超过了题目限制的26。不过复杂度看起来还可以?每个点的layer恰好等于它被遍历的次数。正解要用树的重心去做。

模板题是这个:https://codeforces.com/contest/321/problem/C

这个题我一开始觉得是用直径的中心去做,但是按直径划分的话子树的直径不见得就是原树直径的1/2。可能只减少几个点甚至还会完全一样。

比如:

6 - 5 - 4 - 3 - 2 - 1 - 2 - 3 - 4 - 5 - 6
    6   5   4   3   2
        6   5   4   3
            6   5   4
                6   5
                    6

当前直径为13,去掉了1之后其实左边的直径还有10。并不是除以2。

https://codeforces.com/contest/321/problem/C

const int MAXN = 2e5 + 10;

int n;
vector<int> G[MAXN];
int dep[MAXN];
int layer[MAXN];


int find_max_dep_leaf (int u, int p) {
    dep[u] = dep[p] + 1;
    int max_dep_leaf = u;
    for (const int &v : G[u]) {
        if (v == p || layer[v] != 0) {
            continue;
        }
        int leaf = find_max_dep_leaf (v, u);
        if (dep[leaf] > dep[max_dep_leaf]) {
            max_dep_leaf = leaf;
        }
    }
    return max_dep_leaf;
}

int find_center (int u, int p, int max_dep_leaf) {
    if (u == max_dep_leaf) {
        return max_dep_leaf;
    }
    for (const int &v : G[u]) {
        if (v == p || layer[v] != 0) {
            continue;
        }
        int res = find_center (v, u, max_dep_leaf);
        if (res == 0) {
            continue;
        }
        if (dep[u] == (dep[max_dep_leaf] + 1) / 2) {
            res = u;
        }
        return res;
    }
    return 0;
}


void find_all_centers (int root, int l) {
    if (layer[root] != 0) {
        return;
    }
    int leaf1 = find_max_dep_leaf (root, 0);
    int leaf2 = find_max_dep_leaf (leaf1, 0);
    int center = find_center (leaf1, 0, leaf2);
    layer[center] = l;
    for (const int &v : G[center]) {
        find_all_centers (v, l + 1);
    }
}


void solve() {
    RD (n);
    for (int i = 1; i <= n; ++i) {
        G[i].clear();
        layer[i] = 0;
    }
    for (int i = 1; i <= n - 1; ++i) {
        int u, v;
        RD (u, v);
        G[u].push_back (v);
        G[v].push_back (u);
    }
    find_all_centers (1, 1);

    ll sum_layer = 0;
    for (int i = 1; i <= n; ++i) {
        sum_layer += layer[i];
    }
    WT (sum_layer);
    WTN (layer, n);
}
posted @ 2021-02-03 22:44  purinliang  阅读(56)  评论(0编辑  收藏  举报