題目大意:對於一棵n個結點的無根樹,求出每個結點的最遠點,要求時間複雜度為o(n)。
對於乙個點,距離它最遠的點一定是直徑的端點。①若p已經在直徑上,根據樹的直徑的定義可知q也在直徑上且為直徑的乙個端點證明:我們求直徑的時候,兩次dfs。
兩次bfs(或者dfs)
方法:先從任意一點p出發,找離它最遠的點q,再從點q出發,找離它最遠的點w,w到q的距離就是是的直徑
②若p不在直徑上,我們用反證法,假設此時wq不是直徑,ab是直徑
—>若ab與pq有交點c,由於p到q最遠,那麼pc+cq>pc+ca,所以cq>ca,易得cq+cb>ca+cb,即cq+cb>ab,與ab是直徑矛盾,不成立,如下圖(其中ab,pq不一定是直線,畫成直線是為了方便):
—>若ab與pq沒有交點,m為ab上任意一點,n為pq上任意一點。首先還是np+nq>nq+mn+mb,同時減掉nq,得np>mn+mb,易知np+mn>mb,所以np+mn+ma>mb+ma,即np+mn+ma>ab,與ab是直徑矛盾,所以這種情況也不成立,如下圖:
那麼這個就已經證明了。我們現在只需要把兩個端點求出來,然後對兩個端點進行兩次dfs,更新他們到端點的距離,然後取最大值的就行了。
#include
using
namespace std;
const
int maxn=
1e4+10;
struct e};
vector e[maxn]
;int dp[maxn][2
];int d, k;
int vis[maxn]
;int
dfs(
int u,
int s,
int f)
for(
int i=
0;i.size()
;i++)}
}int
main()
d=k=0;
dfs(1,
0,0)
; d1=k;
//第乙個端點
memset
(vis,0,
sizeof
(vis));
dfs(d1,0,
0);
d2=k;
//第二個端點
memset
(vis,0,
sizeof
(vis));
dfs(d2,0,
1);for
(int i=
1;i<=n;i++
)return0;
}
C 樹上的最遠點對
51nod 1766 vjudge n個點被n 1條邊連線成了一顆樹,給出 a b 和 c d 兩個區間,表示點的標號請你求出兩個區間內各選一點之間的最大距離,即你需要求出max dis i,j a i b,c j d ps 建議使用讀入優化 第一行乙個數字 n n 100000。第二行到第n行每行...
51NOD 1766 樹上的最遠點對
n 個點被n 1條邊連線成了一顆樹,邊有權值wi 有q 個詢問,給出 a b 和 c,d 兩個區間,表示點的標號請你求出兩個區間內各選一點之間的最大距離,即你需要求出 ma x 1 n,q 105,1 wi 104 可以發現最長路徑具有直徑的合併性質,即兩個區間選點的最長路徑端點一定是原本兩個區間最...
51nod1766 樹上的最遠點對
n個點被n 1條邊連線成了一顆樹,給出a b和c d兩個區間,表示點的標號請你求出兩個區間內各選一點之間的最大距離,即你需要求出max dis i,j a i b,c j d ps 建議使用讀入優化 第一行乙個數字 n n 100000。第二行到第n行每行三個數字描述路的情況,x,y,z 1 x,y...