其實題目說那麼多,一句話就是:給定一棵帶權樹與m
mm條路徑,你可以使一條樹上的邊的權值變為0,問你m
mm條路徑的長度的最大值最小是多少。
這道題讓我想到了貨車運輸這道題,但是更難,但方法可以借鑑。
因為這是最大值最小問題,很顯然可以二分答案。
那這個二分判斷怎麼打呢?
我們如果遇到某條邊,所有超時的邊(即超過當前二分的答案)都經過此邊,且最長路徑減當前邊的權值小於等於二分的答案(即把這條邊的權值變為0),就證明答案合法。
否則不合法。
那麼我們再往下分析,怎麼求某條邊被所有超時的邊經過?我們可以想到樹上差分!(關於樹上差分,以後會補更,這裡麻煩大家先自己去學,挺簡單的),把超時的路徑加一,最後跑一遍每一條邊,判斷用上文提到的方法。
我們又想,怎麼知道哪條邊超時了?沒錯,就是lca!(lca鏈結)(我們這裡就用倍增,不用樹鏈剖分了)
想必lca求出來了,求距離也很容易了吧。
只要計算:len
[i]=
dis[
a[i]
]+di
s[b[
i]]−
2∗di
s[lc
a[i]
]len[i]=dis[a[i]]+dis[b[i]]-2*dis[lca[i]]
len[i]
=dis
[a[i
]]+d
is[b
[i]]
−2∗d
is[l
ca[i
]](即當前距離等於點a[i
]a[i]
a[i]
到根的距離加點b[i
]b[i]
b[i]
到根的距離減去它們lca到根的距離)
形象畫圖:
這裡稍微要注意一下,這裡的邊帶了權值,所以計算時不可以用深度dep
depde
p,而是加入乙個距離dis
disdi
s,di
sdis
dis的更新可以在lca遞迴預處理時把當前的邊記錄,即賦值dis
disdi
s為邊權。
我發現許多人都卡在95分,被卡常,差幾毫秒超時了,這裡提供幾種優化:
1.用快讀(快讀鏈結)
2.在樹上差分時用dfs
dfsdf
s序處理(雖然理論上是一樣的,但是迴圈的常數比遞迴的小)這裡可以在lca遞迴預處理時記錄dfs
dfsdf
s序。**:
#include
#include
#include
#define n 300010
using namespace std;
int n,m,x,y,z,max,l,r,mid,ans;
int a[n]
,b[n]
,lca[n]
,len[n]
,cf[n]
;int f[n][21
],dfn[n]
,dfn_tot,dep[n]
,dis[n]
,va[n]
,father[n]
;int head[n]
,next[n*2]
,e[n*2]
,v[n*2]
,tot;
//鏈式前向星
inline
void
read
(int
&x)//快讀加速
inline
intadd
(int x,
int y,
int z)
//鏈式前向星
inline
void
dfs(
int x,
int fa)
//lca遞迴預處理
intlca
(int x,
int y)
//求lca
for(
register
int i=
20;i>=
0;i--)if
(f[x]
[i]&&f[y]
[i]&&f[x]
[i]!=f[y]
[i]) x=f[x]
[i],y=f[y]
[i];
return f[x][0
];}inline
intcheck
(int mid)
//二分判斷函式
intmain()
r=max;
//二分
while
(l<=r)
printf
("%d"
,ans)
;}
Noip2015提高組總結
總體而言noip還行吧,每天前兩題都穩穩地,但是最後一題做得不好。day1,看完題目後,第一題簽到,第二題很直觀想出來了,又畫了個圖驗證了一下,tarjan雖然可能爆棧,但人工棧就沒問題了。第三題認為是dp一類的東西。畢竟是第一次提高組,還是挺緊張的,一二題打得特別仔細特別慢,對拍,肉眼查錯,搞了接...
NOIP2015提高組解析
題目見此 day1 神奇的幻方 裸裸的模擬 其實也可以發現規律 i 1在i的右上方,如果已經有數了,就填在i的下方 include includeusing namespace std int a 50 50 int nx,ny,n int main else elseelse a tx ty i ...
NOIP2015提高組Day2T3 運輸計畫
傳送門 tips 如果兩個點的lca會被反覆用到,就可以拿乙個陣列存下來,避免反覆計算 analysis 又是一道好喵喵喵妙的題啊!樹上差分太棒了,簡直太厲害 不過首先我們得看出來這是一道二分可以解決的問題 然後問題就變成了怎麼check 看看gsj大佬怎麼說吧 code 注意常數因子帶來的程式效率...