1. 程式人生 > >BZOJ_3124_[Sdoi2013]直徑_樹形DP

BZOJ_3124_[Sdoi2013]直徑_樹形DP

light printf 編號 inpu 無向圖 def dep cst 範圍

BZOJ_3124_[Sdoi2013]直徑_樹形DP

Description

小Q最近學習了一些圖論知識。根據課本,有如下定義。樹:無回路且連通的無向圖,每條邊都有正整數的權值來表示其長度。如果一棵樹有N個節點,可以證明其有且僅有N-1 條邊。 路徑:一棵樹上,任意兩個節點之間最多有一條簡單路徑。我們用 dis(a,b)
表示點a和點b的路徑上各邊長度之和。稱dis(a,b)為a、b兩個節點間的距離。
直徑:一棵樹上,最長的路徑為樹的直徑。樹的直徑可能不是唯一的。
現在小Q想知道,對於給定的一棵樹,其直徑的長度是多少,以及有多少條邊滿足所有的直徑都經過該邊。

Input

第一行包含一個整數N,表示節點數。
接下來N-1行,每行三個整數a, b, c ,表示點 a和點b之間有一條長度為c
的無向邊。

Output


共兩行。第一行一個整數,表示直徑的長度。第二行一個整數,表示被所有
直徑經過的邊的數量。

Sample Input


6
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100

Sample Output

1110
2


【樣例說明】
直徑共有兩條,3 到2的路徑和3到6的路徑。這兩條直徑都經過邊(3, 1)和邊(1, 4)。

HINT

對於100%的測試數據:2≤N≤200000,所有點的編號都在1..N的範圍內,
邊的權值≤10^9。


邊權非負,可以用一個基於貪心的方法求直徑。

以1為根進行dfs,求出每個點到根的距離dis1,令rt1為最大的一個點。

以rt1為根就能拽出來一條直徑rt1---rt2,求出每個點到根的距離dis2。

所求的那些邊一定是連續的,如果不連續則中間的那個一定可以替代邊上的邊。

考慮dis2[i]=dis2[rt2]的那些點i,一定可以和rt1形成又一條直徑,於是可以把i和rt2的lca一下的那些邊摳掉。

然後反過來再做一遍就可以啦。

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 200050
typedef long long ll;
int head[N],to[N<<1],nxt[N<<1],val[N<<1],cnt,n,fa[N],dep[N],f[25][N],dis3[N];
ll dis1[N],dis2[N];
int rt1,rt2;
inline void add(int u,int v,int w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dfs1(int x,int y) {
    int i;
    if(dis1[x]>dis1[rt1]) rt1=x;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dis1[to[i]]=dis1[x]+val[i];
            dfs1(to[i],x);
        }
    }
}
void dfs2(int x,int y) {
    int i; fa[x]=y; f[0][x]=y;
    if(dis2[x]>dis2[rt2]) rt2=x;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dep[to[i]]=dep[x]+1;
            dis2[to[i]]=dis2[x]+val[i];
            dfs2(to[i],x);
        }
    }
}
int lca(int x,int y) {
    if(dep[x]<dep[y]) swap(x,y);
    int i;
    for(i=20;i>=0;i--) {
        if(f[i][x]&&dep[f[i][x]]>=dep[y]) x=f[i][x];
    }
    if(x==y) return x;
    for(i=20;i>=0;i--) {
        if(f[i][x]&&f[i][y]&&f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
    }
    return f[0][x];
}
void dfs3(int x,int y) {
    int i; f[0][x]=y;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dep[to[i]]=dep[x]+1;
            dis3[to[i]]=dis3[x]+val[i];
            dfs3(to[i],x);
        }
    }
}
int main() {
    scanf("%d",&n);
    int i,x,y,z;
    for(i=1;i<n;i++) {
        scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z);
    } 
    dfs1(1,0);
 
    dfs2(rt1,0);
    int j;
    for(i=1;(1<<i)<=n;i++) {
        for(j=1;j<=n;j++) f[i][j]=f[i-1][f[i-1][j]];
    }
    int U=rt2;
    for(i=1;i<=n;i++) if(dis2[i]==dis2[rt2]) U=lca(U,i);
    memset(f,0,sizeof(f));
    dfs3(rt2,0);
    for(i=1;(1<<i)<=n;i++) {
        for(j=1;j<=n;j++) f[i][j]=f[i-1][f[i-1][j]];
    }
    int D=rt1;
    // printf("%d %d\n",rt1,rt2);
    for(i=1;i<=n;i++) if(dis3[i]==dis3[rt1]) D=lca(D,i); 
    printf("%lld\n%d\n",dis2[rt2],dep[D]-dep[U]);
}

BZOJ_3124_[Sdoi2013]直徑_樹形DP