題解 Luogu P1099 樹網的核

2022-08-16 18:27:18 字數 1382 閱讀 2628

這題資料是真的水啊。。。

昨天模擬賽考了這題,很多人都是 $o(n^3)$ 水過,但我認為,要做就做的足夠好(其實是我根本沒想到 $o(n^3)$ 的做法),然後就開始想 $o(n)$ 的解法。

首先看題目,前面一大堆看似是廢話,其實還是有很大用處的。

問題描述中提到了樹的中心,但後面卻貌似沒有用到,其實中心是給我們帶來提示的。

既然是求最小偏心距,那必然是要在直徑上找,不然偏心距並不能有過多的減少,所以第一步,定下在直徑上找。

然後直徑上找也要講究方法,假如整條路徑在中心的左邊或右邊,那麼偏心距就會過大了(s太小了也沒辦法了)。所以,如果s足夠大的話,應該將路徑放在中間(指的是路徑左端點到直徑的左端點與路徑右端點到直徑右端點的距離差最小),所以先定下中心所在的邊上的兩個端點(如果s太小就用兩端點中靠近中心的乙個端點),然後哪一邊的偏心距(部分的)大,就往哪邊拓展,相同則同時拓展。

有兩點需要注意注意:

一、如果有兩條或更多直徑,走到幾條直徑的分叉點時,就停止往這邊拓展了,並且如果另一邊的偏心距(部分的)小於這邊,那麼就不必拓展了,反正拓展了後偏心距還是這邊的值。

二、只有一條直徑時,要注意找所選路徑上所有的偏心距,然後取大,再與直徑兩端點到路徑兩端點的距離取大(這裡是指左端點與左端點,右端點與右端點的距離)

然後就愉快的ac了!(實測bzoj同樣能過)

**如下:(30ms,沒進最優解qaq)

#includeinline int read()

while(c>='0'&&c<='9')r=(r<<1)+(r<<3)+c-'0',c=getchar();

return r*f;

}struct ee[1000001];

int n,s_e,s,head[500005],dis[500005],s,t,zj,next[2][500005][2],zx[4],f[2][500005],ans=1e9;//f是部分的偏心距,next是從s(或t)出發的下乙個點(直徑上)

bool bj[2][500005],jg[500005];//jg就是指直徑上的點,bj指的是是不是直徑分叉口

inline int max(int a,int b)

inline int min(int a,int b)

find_zx(v,dis+val);

}int ansl,ansr,anss=-1e9;

void solve(int l,int r,int dis)

else if(bj[0][r]||bj[1][r]){

if(next[1][l][1]+dis<=s&&f[0][r]f[1][l]&&next[0][r][1]+dis<=s)solve(l,next[0][r][0],dis+next[0][r][1]);

else if(f[0][r]~~完結偷偷撒花~~✿✿ヽ(°▽°)ノ✿

luogu P1099 樹網的核

題面傳送門 先兩遍dfs dfsdf s跑出樹的直徑。因為所有樹的直徑都是相類似的,所以只要跑一條直徑就好了。然後在這條直徑上尺取。最後對於直徑上每個點的子樹不經過直徑上的邊求距離取最大值即可,這一步很難想,因為如果不取最大值那麼就會漏掉答案因為無論如何都是要有這條邊的權值的。完美o n o n o...

洛谷 P1099 樹網的核 題解

樓上的大佬似乎都用的dfs,像我這種蒟蒻只會用暴力的floyd演算法。不過,看到這道題規模只有300,floyd演算法不會有問題。首先用floyd演算法預處理點對之間的距離,接下來窮舉每一對點構成的路徑 假裝每一條路徑就是樹網的核 如果路徑長 s,則計算其它點到該路徑的最大距離,取窮舉到的所有路徑中...

BZOJ 1099 樹網的核

題面 搞了三個多小時。noip時的資料很水,直接暴力n 3過。我們考慮優化,首先可以貪心,我們要在直徑上選肯定越插長越好,所以n 2其實就可以解決。但這還不夠,根據直徑的最長性,我們可以用乙個單調佇列優化。include include include include include using n...