聯盟(樹的直徑)

2022-04-14 05:11:09 字數 1552 閱讀 8869

給你一棵樹,你可以選擇斷開一條邊再連上一條邊使樹的直徑最小,求最小直徑,可以斷的邊,任意一組可以斷的點和新連的點。

算是求樹上直徑的綜合運用。

先考慮乙個問題:現在有兩棵樹,直徑分別為$l_1$,$l_2$,

那麼將兩棵樹合併後新樹的直徑最小為$\max(l_1,l_2,\lceil\frac\rceil+\lceil\frac\rceil+1)$。

顯然合併時的最優選擇為連上兩棵樹的中點,因為任何其他位置都不會使新樹的直徑更短。

本題中我們先dfs預處理出直徑的兩個端點,標記出一條直徑。

然後分別以兩個端點為根樹形dp出每個子樹內的最長鏈。

列舉斷邊,若斷邊在當前直徑上,那麼我們可以用預處理出的dp值求出新樹的直徑。

若不在直徑上,那麼一棵子樹的直徑為原直徑,另乙個子樹的直徑可用dp表示。

記錄一下最小值以及取最小值的樹的編號即可。

至於第三問,我們隨便找到一條符合的邊,找到切斷它後兩棵子樹的直徑的中點連邊即可。

#include#include#include#includeusing namespace std;

#define r register

#define ll long long

inline ll read()

return aa;

}inline int max(int x,int y)

const int n=300003,m=600003;

struct edgeed[n];

int tot,first[n],ver[m],nxt[m];

inline void add(int x,int y)

int n,f[n],fg[n],g[m],ve[n],ansi;

void dp(int x,int fa,int ei)

fg[x]=max(fg[x],g[ei]);

}int dis[n],pre[n],vi[n],pi,pj;

void dfsi(int x,int fa)

}int dfsj(int x,int fa,int dep)

return 0;

}void dfsk(int x,int fa,int lim)

}void getline()

void solve(int x,int y)

int main(); }

dis[1]=0;pj=1;dfsi(1,1);pi=pj;

dis[pi]=0;dfsi(pi,pi);ansi=dis[pj];

getline();//zhao dao zhi jing

dp(pj,pj,1);dp(pi,pi,1);

for(r int i=1,x,y,u,v,z;iprintf("%d\n%d ",ansi,ve[0]);

for(r int i=1;i<=ve[0];++i)printf("%d ",ve[i]);puts("");

solve(ed[ve[1]].u,ed[ve[1]].v);return 0;}/*

41 2

2 3

3 4

*/

SDOI2013 直徑(樹的直徑)

小q最近學習了一些圖論知識。根據課本,有如下定義。樹 無迴路且連通的無向圖,每條邊都有正整數的權值來表示其長度。如果一棵樹有n個節點,可以證明其有且僅有n 1 條邊。路徑 一棵樹上,任意兩個節點之間最多有一條簡單路徑。我們用 dis a,b 表示點a和點b的路徑上各邊長度之和。稱dis a,b 為a...

樹的直徑 板子

不帶解釋版模板o n 常數較大,但是可以知道樹上每一點到直徑端點的距離,這個大多時候都很有用 struct node e maxn 2 ll dis1 maxn dis2 maxn int st,ed,max len void dd int u,int fa,int len,int flag fil...

樹的直徑相關

一.樹直徑的定義.顯然一棵樹可以有不止一條直徑.二.樹直徑的求解.一般來說樹的直徑可以用樹形dp來求.設f i 0 1 f i 0 1 f i 0 1 表示在i ii的子樹中以i ii為一端的最長 次長鏈長度,我們可以很容易dp出來這個值,樹的直徑就是f i 0 f i 1 f i 0 f i 1 ...