TyvjP1520 树的直径(模板)

来源:互联网 发布:照片转十字绣软件 编辑:程序博客网 时间:2024/05/29 02:20

题目链接

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

我在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和g数组
这样当前点对答案的贡献就是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;}
原创粉丝点击