【挖坑记】JZOJ 4727 挺进

题目大意

一棵树,求出随机断一条边后,两个联通块直径和的最大值。
n<=100000,边长<=100000
时间限制 1s
空间限制 256M

解题思路

对于树上每一个点,预处理出以下数据:
1、每棵子树的根节点到叶节点的最大值、次大值和第三大值d1,d2,d3;
2、每棵子树内直径长度f;
3、每棵子树的子结点中f[son]的最大值和次大值;
4、这个点与该子树以外的点的距离dist的最大值;
预处理之后,枚举切断哪条边,然后O(1)得出直径和即可。

#include
#include
#include
#define maxn 200006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;

struct poi
{
    int x,y;
    poi *nex;
} *a[maxn];
int i,n,x,y,z,fa[maxn];
ll ans,f[maxn],d1[maxn],d2[maxn],d3[maxn],jl[maxn];
ll jl2[maxn],s1[maxn],s2[maxn],di[maxn],anc[maxn];
void link(int x,int y,int z)
{
    poi *p=new poi;
    p->x=y;
    p->y=z;
    p->nex=a[x];
    a[x]=p;
    return;
}
void dfs(int x)
{
    poi *p=new poi;
    for(p=a[x];p;p=p->nex)
        if (p->x!=fa[x])
        {
            int u=p->x;
            fa[u]=x;
            dfs(u);

            if (d1[u]+p->y>d1[x])
            {
                d3[x]=d2[x];
                d2[x]=d1[x];
                jl2[x]=jl[x];
                d1[x]=d1[u]+p->y;
                jl[x]=u;
            } else if (d1[u]+p->y>d2[x])
            {
                d3[x]=d2[x];
                d2[x]=d1[u]+p->y;
                jl2[x]=u;
            } else if (d1[u]+p->y>d3[x])
                d3[x]=d1[u]+p->y;

            if (f[u]>s1[x])
            {
                s2[x]=s1[x];
                s1[x]=f[u];
                di[x]=u;
            } else if (f[u]>s2[x]) 
                s2[x]=f[u];

            f[x]=max(f[x],f[u]);
        }
    f[x]=max(f[x],d1[x]+d2[x]);
    return;
}
void redfs(int x)
{
    poi *p=new poi;
    for(p=a[x];p;p=p->nex)
        if (p->x!=fa[x])
        {
            int u=p->x;
            ll t1,t2;
            t1=f[u];

            if (u==jl[x]) t2=anc[x]+d2[x];
            else t2=anc[x]+d1[x];

            if (u==di[x]) t2=max(t2,s2[x]);
            else t2=max(t2,s1[x]);

            if (u==jl[x]) t2=max(t2,d2[x]+d3[x]);
            else if (u==jl2[x]) t2=max(t2,d1[x]+d3[x]);
            else t2=max(t2,d1[x]+d2[x]);

            ans=max(ans,t1+t2);

            redfs(u);
        }
    return;
}
void dfss(int x)
{
    poi *p=new poi;
    for(p=a[x];p;p=p->nex)
        if (p->x!=fa[x])
        {
            int u=p->x;
            anc[u]=anc[x]+p->y;
            if (u==jl[x]) anc[u]=max(anc[u],d2[x]+p->y);
            else anc[u]=max(anc[u],d1[x]+p->y);

            dfss(u);
        }
    return;
}
int main()
{
    scanf("%d",&n);
    fr(i,1,n-1)
    {
        scanf("%d%d%d",&x,&y,&z);
        link(x,y,z),link(y,x,z);
    }
    dfs(1);
    dfss(1);
    redfs(1);
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(挖坑记,树)