TyvjP1520 树的直径(模板)

题目链接

分析:
我曾经谈过树的直径
但是只停留在理论阶段,不会实现
今天就来填这个史前巨坑

我在blog提到过:
设计状态:
f[i]表示i这棵子树中经过i的最长路径(可以经过i也可以是i作为途中一点)
g[i]表示i这棵子树中,以i为端点的最长路径

f[fa]=max(firstmax{w(fa,u)+g[u]},0)+max(secondmax{w(fa,u)+g[u]},0)
g[fa]=max{w(fa,u)+g[u]}

然而我发现如果真的按照上述的方程转移的话,就很tomato难受
我们可以简化一下状态:
f[i]表示i这棵子树中,以i为端点的最长链
g[i]表示i这棵子树中,以i为端点的次长链
这样当前点对答案的贡献就是f[i]+g[i]

复杂度:O(n)

这里写图片描述

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=100010;
int f[N],g[N];
struct node{
    int x,y,nxt,v;
};
node way[N<<1];
int st[N],tot=0,ans=0,n;

void add(int u,int w,int z)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}

void dfs(int now,int fa)
{
    g[now]=0; f[now]=0;
    for (int i=st[now];i;i=way[i].nxt)
        if (way[i].y!=fa)
        {
            dfs(way[i].y,now);
            int len=way[i].v+f[way[i].y];
            if (len>f[now])
            {
                g[now]=f[now];
                f[now]=len;
            }
            else if (len>g[now])
            {
                g[now]=len;
            }
        }
    ans=max(ans,f[now]+g[now]);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int u,w,z;
        scanf("%d%d%d",&u,&w,&z);
        add(u,w,z);
        add(w,u,z);
    }
    dfs(1,0);
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673140.html