[SDOI2013]直徑(樹的直徑)
阿新 • • 發佈:2018-08-23
str 學習 sin clas long long ont tro 給定 pac
但是我並不知道為什麽要從起點推一遍收縮的一段,再從樹的直徑的末尾推一遍收縮的另一端。這兩段之間的路徑就是解。
但是一遍循環是推不出的,必須循環兩次??
如果有巨佬一個循環搞出了兩個段點可以告訴本蒟蒻qwq。
[SDOI2013]直徑
題目描述
小Q最近學習了一些圖論知識。根據課本,有如下定義。樹:無回路且連通的無向圖,每條邊都有正整數的權值來表示其長度。如果一棵樹有N個節點,可以證明其有且僅有N-1 條邊。
路徑:一棵樹上,任意兩個節點之間最多有一條簡單路徑。我們用 dis(a,b)表示點a和點b的路徑上各邊長度之和。稱dis(a,b)為a、b兩個節點間的距離。
直徑:一棵樹上,最長的路徑為樹的直徑。樹的直徑可能不是唯一的。
現在小Q想知道,對於給定的一棵樹,其直徑的長度是多少,以及有多少條邊滿足所有的直徑都經過該邊。
輸入輸出格式
輸入格式:
第一行包含一個整數N,表示節點數。 接下來N-1行,每行三個整數a, b, c ,表示點 a和點b之間有一條長度為c的無向邊。
輸出格式:
共兩行。第一行一個整數,表示直徑的長度。第二行一個整數,表示被所有直徑經過的邊的數量。
輸入輸出樣例
輸入樣例#1: 復制
6
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100
輸出樣例#1: 復制
1110
2
說明
【樣例說明】 直徑共有兩條,3 到2的路徑和3到6的路徑。這兩條直徑都經過邊(3, 1)和邊(1, 4)。
對於100%的測試數據:2<=N<=200000,所有點的編號都在1..N的範圍內,邊的權值<=10^9。
題解
這道題目比較玄學。
我們知道對一顆樹不止一條直徑,那麽被所有直徑經過的邊,
隨著直徑的分叉而不斷收縮。
而直徑的分叉點一定是在直徑上的。
但是一遍循環是推不出的,必須循環兩次??
如果有巨佬一個循環搞出了兩個段點可以告訴本蒟蒻qwq。
代碼
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int N=200001; ll dis[N],maxx,s,t; ll n,m,num,head[N],vis[N]; struct node{ int to,nex; ll v; }e[N<<1]; ll dep[N],ff[N],l,r,ans,son[N]; void add(int from,int to,ll v){ num++; e[num].to=to; e[num].v=v; e[num].nex=head[from]; head[from]=num; } ll read(){ ll x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } void dfs(int x,int fa){ for(int i=head[x];i;i=e[i].nex){ int v=e[i].to;if(v==fa)continue;ff[v]=x; dis[v]=dis[x]+e[i].v;dfs(v,x); } } void dfs2(int u,int fa){ dep[u]=0;ll maxn=0; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to;if(v==ff[u]||vis[v]==1)continue; dfs2(v,u);maxn=max(maxn,dep[v]+e[i].v); } dep[u]=maxn; } int main(){ n=read(); for(int i=1;i<n;i++) { ll x=read(),y=read(),z=read(); add(x,y,z);add(y,x,z); } dfs(1,0); for(int i=1;i<=n;i++){if(dis[i]>maxx)maxx=dis[i],s=i;dis[i]=0;} dfs(s,0);maxx=0; for(int i=1;i<=n;i++)if(dis[i]>maxx)maxx=dis[i],t=i; printf("%lld\n",maxx); l=t;r=s; int now=t; while(now!=s){ vis[now]=1;son[ff[now]]=now;now=ff[now]; } now=t; while(now!=s){ dep[now]=0; dfs2(now,0); if(dep[now]==maxx-dis[now])l=now; now=ff[now]; } now=s; while(now){ dfs2(now,0); if(dep[now]==dis[now])r=now; now=son[now]; } while(l!=r&&l){ l=ff[l];ans++; } printf("%lld\n",ans); return 0; }
[SDOI2013]直徑(樹的直徑)