【挖坑記】JZOJ 4727 挺進

題目大意

一棵樹,求出隨機斷一條邊後,兩個聯通塊直徑和的最大值。
n<=100000,邊長<=100000
時間限制 1s
空間限制 256M

解題思路

對於樹上每一個點,預處理出以下數據:
1、每棵子樹的根節點到葉節點的最大值、次大值和第三大值d1,d2,d3;
2、每棵子樹內直徑長度f;
3、每棵子樹的子結點中f[son]的最大值和次大值;
4、這個點與該子樹以外的點的距離dist的最大值;
預處理之後,枚舉切斷哪條邊,然後O(1)得出直徑和即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章