求树的直径

前言

树的直径指树上距离最远的两点间的距离,它在树上问题上有许多应用,往往通过树的直径的性质可以将一个高时间复杂度的解法变为线性求解。

树型DP求解树的直径的方法:复杂度 O(N)

DP求直径的方法是对于每个点记录这个点子树中的最长链及与最长链处于不同子树中的次长链,用每个点的最长链+次长链更新直径,然后再将最长链上传到父节点更新父节点的最长链或次长链。这种求法适用于所有求树的直径的情况。

我们用 f1[x] 代表 x 为根的子树最长链,f2[x] 代表 x 为根的子树次长链

每次先更新最长,再更新次长

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 1e6 + 10;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct edge {
    int v,w,nxt;
}e[maxn];

int head[maxn],f1[maxn],f2[maxn];
int cnt,ans;
void add_edge(int u,int v,int w) {
    e[++cnt].nxt = head[u];
    e[cnt].w = w;
    e[cnt].v = v;
    head[u] = cnt;
}


void dfs(int u,int f) {
    f1[u] = f2[u] = 0;
    for (int i = head[u];~i;i = e[i].nxt) {
        int v = e[i].v;
        if (v == f)
            continue;
        dfs(v,u);
        if (f1[u] < f1[v] + e[i].w) {
            f2[u] = f1[u];
            f1[u] = f1[v] + e[i].w;
        }
        else if (f2[u] < f1[v] + e[i].w)
            f2[u] = f1[v] + e[i].w;
    }
    ans = max(ans,f1[u]+f2[u]);
}

int main() {
    //freopen("../in.txt","r",stdin);
    memset(f1,0,sizeof(f1));
    memset(f2,0, sizeof(f2));
    memset(head,-1, sizeof(head));
    cnt = 0,ans = 0;
    int u,v,w;
    while (~scanf("%d%d%d",&u,&v,&w)) {
        add_edge(u,v,w);
        add_edge(v,u,w);
    }
    dfs(1,0);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/-Ackerman/p/12332457.html