1. 程式人生 > >樹型大融合——NOIP提高組2015 D1T3 【運輸計劃】

樹型大融合——NOIP提高組2015 D1T3 【運輸計劃】

n-1 建設 dash down get 二分 描述 飛船 func

下午用一個小時看了一下樹上差分,打了個差分模板,A了3題,真的爽!

題目描述:

公元2044 年,人類進入了宇宙紀元。

L 國有 n 個星球,還有 n-1 條雙向航道,每條航道建立在兩個星球之間,這 n-1 條航道連通了 L 國的所有星球。

小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如:有一艘物流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去。顯然,飛船駛過一條航道是需要時間的,對於航道j,任意飛船駛過它所花費的時間為 tj,並且任意兩艘飛船之間不會產生任何幹擾。

為了鼓勵科技創新, L 國國王同意小 P 的物流公司參與 L 國的航道建設,即允許小P 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。

在蟲洞的建設完成前小 P 的物流公司就預接了 m 個運輸計劃。在蟲洞建設完成後,這 m 個運輸計劃會同時開始,所有飛船一起出發。當這 m 個運輸計劃都完成時,小 P 的物流公司的階段性工作就完成了。

如果小 P 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 P 的物流公司完成階段性工作所需要的最短時間是多少?

數據範圍:

n<=300000,m<=300000

思路分析:

首先得寫個倍增求LCA求個鏈長,這應該沒問題吧,我之前講過的。

那麽再看問題,“使最大的運輸時間最少”——某王 定理之二十一:任何求最大值最小,最小值最大的問題十有八九是二分答案。

嗯,很好,讓我們考慮二分答案這種神奇的東西。

對於我們二分出的答案mid,我們應該怎麽來判斷它是否合法呢?

首先讓我們找出這m條鏈中長度大於mid的,求出鏈的數量num以及最長鏈的長度len。

顯然,當這num條邊中都經過一條長度至少為(len-mid)的邊,那麽當我們刪去這條邊後,這個答案就是合法的,因為原本所有長度大於mid的鏈長度都會小於等於mid。

那麽我們應該怎麽找這num條鏈都經過的邊呢?——樹上差分嘛,沒有爭議的。

代碼實現:

var
  f:array[0..300000,0..20]of longint;
  vis:array[0..300000]of boolean;
  next,vet,dist:
array[0..600000]of longint; head,cnt,depth,g,d,len,u,v,grand:array[0..300000]of longint; ans,i,j,n,m,tot,x,y,z,max,num,k,l,r,mid:longint; flag:boolean; procedure add(x,y,z:longint); begin inc(tot); next[tot]:=head[x]; vet[tot]:=y; head[x]:=tot; dist[tot]:=z; end; procedure dfs(u,dep,dis:longint); var i,v:longint; begin depth[u]:=dep; vis[u]:=true; for i:=1 to 20 do f[u,i]:=f[f[u,i-1],i-1]; i:=head[u]; while i<>0 do begin v:=vet[i]; if not vis[v] then begin f[v,0]:=u; d[v]:=dis+dist[i]; dfs(v,dep+1,d[v]); end; i:=next[i]; end; end; function lca(a,b:longint):longint; var i,t:longint; begin if depth[a]>depth[b] then begin t:=a; a:=b; b:=t; end; for i:=20 downto 0 do if depth[f[b,i]]>=depth[a] then b:=f[b,i]; if a=b then exit(a); for i:=20 downto 0 do if f[a,i]<>f[b,i] then begin a:=f[a,i]; b:=f[b,i]; end; exit(f[a,0]); end; procedure getans(u,father:longint); var i,v:longint; begin g[u]:=cnt[u]; i:=head[u]; while i<>0 do begin v:=vet[i]; if v<>father then begin getans(v,u); g[u]:=g[u]+g[v]; if (g[v]=num)and(dist[i]>=k) then flag:=true; end; i:=next[i]; end; end; function check(x:longint):boolean; var i:longint; begin flag:=false; max:=0; num:=0; fillchar(g,sizeof(g),0); fillchar(cnt,sizeof(cnt),0); for i:=1 to m do if len[i]>x then begin inc(cnt[u[i]]); inc(cnt[v[i]]); cnt[grand[i]]:=cnt[grand[i]]-2; inc(num); if len[i]>max then max:=len[i]; end; k:=max-x; getans(1,0); exit(flag); end; begin read(n,m); for i:=1 to n-1 do begin read(x,y,z); add(x,y,z); add(y,x,z); end; dfs(1,1,0); for i:=1 to m do begin read(u[i],v[i]); grand[i]:=lca(u[i],v[i]); len[i]:=d[u[i]]+d[v[i]]-2*d[grand[i]]; if len[i]>max then max:=len[i]; end; l:=1; r:=max; while l<=r do begin mid:=(l+r)div 2; if check(mid) then begin r:=mid-1; ans:=mid; end else l:=mid+1; end; writeln(ans); end.

樹型大融合——NOIP提高組2015 D1T3 【運輸計劃】