SCUT

https://scut.online/p/274

首先要判断是一颗树,并且找出树的直径。

是一棵树,首先边恰好有n-1条,其次要连通,这两个条件已经充分了,当然判环可以加速。

两次dfs找出直径,一边叫做L,另一边叫做R。(第一次写这个)

然后树形dp。

规定其中一个叶子作为树根。然后fx表示从x向下(叶子)走能走到的最远距离,这个非常简单。

然后漏了什么情况呢?从x向上走的情况。

这个时候要从根开始维护一个叫做gx的数组,那么每次孩子v的gx就是父亲u的gx(继续向上走)和u的fx(从父亲开始往下走)的最大值。注意这个时候往下走的不能走回去v,所以要记录两个fx,并且记录大的那个是走哪个方向的。

边界:在叶子/树根等不能走的位置,根据定义,距离为0,点序号为本身。

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

const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;

struct Edge {
    int v, w;
};

vector<Edge> e[MAXN];

void init0(int n) {
    for(int i = 0; i <= n; ++i)
        e[i].clear();
}

int cnt, vis[MAXN], dis[MAXN], maxdis, L, R;

void init1(int n) {
    memset(vis, false, sizeof(vis[0]) * (n + 1));
    memset(dis, 0, sizeof(dis[0]) * (n + 1));
    cnt = 0, maxdis = 0;
}

bool dfs1(int id, int fa) {
    vis[id] = true, ++cnt;
    for(auto p : e[id]) {
        int v = p.v, w = p.w;
        if(v == fa)
            continue;
        if(vis[v])
            return false;
        dis[v] = dis[id] + w;
        if(dis[v] > maxdis)
            maxdis = dis[v], L = v;
        if(dfs1(v, id) == false)
            return false;
    }
    return true;
}

void init2(int n) {
    memset(dis, 0, sizeof(dis[0]) * (n + 1));
    maxdis = 0;
}

void dfs2(int id, int fa) {
    for(auto p : e[id]) {
        int v = p.v, w = p.w;
        if(v == fa)
            continue;
        dis[v] = dis[id] + w;
        if(dis[v] > maxdis)
            maxdis = dis[v], R = v;
        dfs2(v, id);
    }
}

struct F {
    int v, w, s;
    F(int v = 0, int w = 0, int s = 0): v(v), w(w), s(s) {}
} f[MAXN], f2[MAXN], tmp;

void maintainF(int id) {
    if(tmp.w > f2[id].w || tmp.w == f2[id].w && tmp.v < f2[id].v) {
        f2[id] = tmp;
        if(f2[id].w > f[id].w || f2[id].w == f[id].w && f2[id].v < f[id].v)
            swap(f[id], f2[id]);
    }
}

void dfs3(int id, int fa) {
    f[id] = f2[id] = F(id, 0, -1);
    for(auto p : e[id]) {
        int v = p.v, w = p.w;
        if(v == fa)
            continue;
        dfs3(v, id);
        tmp.w = f[v].w + w, tmp.v = f[v].v, tmp.s = v;
        maintainF(id);
    }
}

struct G {
    int v, w;
} g[MAXN];

F getF(int id, int fa) {
    if(f[fa].s == id)
        return f2[fa];
    return f[fa];
}

void maintainG(int id, int fa, int faw) {
    if(fa == 0) {
        g[id].w = 0;
        g[id].v = id;
        return;
    }
    tmp = getF(id, fa);
    if(g[fa].w > tmp.w) {
        g[id].w = g[fa].w + faw;
        g[id].v = g[fa].v;
    } else if(g[fa].w == tmp.w) {
        g[id].w = g[fa].w + faw;
        g[id].v = min(tmp.v, g[fa].v);
    } else {
        g[id].w = tmp.w + faw;
        g[id].v = tmp.v;
    }
}

void dfs4(int id, int fa, int faw) {
    maintainG(id, fa, faw);
    for(auto p : e[id]) {
        int v = p.v, w = p.w;
        if(v == fa)
            continue;
        dfs4(v, id, w);
    }
}

int getFG(int id) {
    if(f[id].w > g[id].w)
        return f[id].v;
    else if(f[id].w == g[id].w)
        return min(f[id].v, g[id].v);
    return g[id].v;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m, k;
    while(~scanf("%d%d%d", &n, &m, &k)) {
        if(m != n - 1) {
            for(int i = 1, u, v, w; i <= m; ++i)
                scanf("%d%d%d", &u, &v, &w);
            puts("There is no B-Tree");
            continue;
        }
        init0(n);
        for(int i = 1, u, v, w; i <= m; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            e[u].push_back({v, w});
            e[v].push_back({u, w});
        }
        init1(n);
        if(dfs1(1, 0) == false || cnt != n) {
            puts("There is no B-Tree");
            continue;
        }
        init2(n);
        dfs2(L, 0);
        if(dis[R] > k) {
            puts("There is no B-Tree");
            continue;
        }
        dfs3(R, 0);
        dfs4(R, 0, 0);
        for(int i = 1; i <= n; ++i)
            printf("%d
", getFG(i));
    }
}
原文地址:https://www.cnblogs.com/Yinku/p/11308595.html