BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)
NOIP2015 运输计划
Description
公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
Input
第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n
Output
输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
Sample Input
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
Sample Output
11
HINT
将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。
将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。
将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。
将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。
将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。
故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。
Source
分析:
二分还是很显然的,二分花费时间,对于这棵树,没超过这个时间的计划可以不用管,对于超过这一时间的运输计划,我们需要利用虫洞使它们时间缩小至允许范围内。显然,这个虫洞必须要在所有超时计划路径的交集中,同时超时计划中最耗时的点减去虫洞的边权后必须在允许范围内。我们可以利用差分,对于每个超时计划,我们在起点和终点+1,并在它们lca点与其父亲连的边-2,从下往上统计,如果某点当前数字和=超时计划总数,并且使所有计划都在允许时间内,则该点可作为虫洞。
别的网站测有95分,bzoj空间太小了会爆
代码:
program transport; type point=^node; node=record x,v:longint; next:point; end; const num=300000; var a:array[0..num]of point; q:array[0..num*3]of longint; h:array[0..25,0..num*3]of longint; w:array[0..num,1..2]of longint; r,c,b,f,d,s,v:array[0..num]of longint; pl:array[0..25]of longint; n,i,m,x,y,t:longint; len,make,maxn:longint; procedure add(x,y,v:longint); var p:point; begin new(p); p^.x:=y; p^.v:=v; p^.next:=a[x]; a[x]:=p; end; procedure dfs(x,y,deep:longint); var p:point; begin new(p); p:=a[x]; d[x]:=deep; inc(len); q[len]:=x; r[x]:=len; while p<>nil do begin if p^.x<>y then begin s[p^.x]:=s[x]+p^.v; dfs(p^.x,x,deep+1); end; p:=p^.next; inc(len); q[len]:=x; end; end; procedure dfs1(x,y,sum:longint); var p:point; begin new(p); p:=a[x]; while p<>nil do begin if p^.x<>y then begin dfs1(p^.x,x,sum); if c[p^.x]>=sum then if p^.v>make then make:=p^.v; inc(c[x],c[p^.x]); end; p:=p^.next; end; inc(c[x],b[x]); end; procedure work; var i,j,x,y:longint; begin for i:=1 to len do h[0,i]:=q[i]; pl[0]:=1; for i:=1 to trunc(ln(len)/ln(2)) do pl[i]:=pl[i-1]*2; for i:=1 to trunc(ln(len)/ln(2)) do for j:=1 to len+1-2*i do begin x:=h[i-1,j]; y:=h[i-1,j+pl[i-1]]; if d[x]<d[y] then h[i,j]:=x else h[i,j]:=y; end; end; function lca(x,y:longint):longint; var i,t:longint; begin x:=r[x]; y:=r[y]; if x>y then begin t:=x; x:=y; y:=t; end; i:=trunc(ln(y-x+1)/ln(2)); x:=h[i,x]; y:=h[i,y-pl[i]+1]; if d[x]<d[y] then exit(x) else exit(y); end; function cheak(mid:longint):boolean; var i,maxant,sum:longint; begin fillchar(c,sizeof(c),0);fillchar(b,sizeof(b),0); maxant:=0; sum:=0; for i:=1 to m do if v[i]>mid then begin inc(c[w[i,1]]); inc(c[w[i,2]]); dec(b[f[i]],2); if v[i]>maxant then maxant:=v[i]; inc(sum); end; make:=0; dfs1(1,0,sum); if make=0 then exit(false); if maxant-make>mid then exit(false); exit(true); end; procedure solve; var l,r,ans,mid:longint; begin l:=1; r:=maxn*2; while l<=r do begin mid:=(l+r) div 2; if cheak(mid) then begin ans:=mid; r:=mid-1; end else l:=mid+1; end; writeln(ans); end; begin readln(n,m); fillchar(r,sizeof(r),0); for i:=1 to n-1 do begin readln(x,y,t); add(x,y,t); add(y,x,t); end; len:=0; s[1]:=0; dfs(1,0,1); work; for i:=1 to m do begin readln(w[i,1],w[i,2]); f[i]:=lca(w[i,1],w[i,2]); v[i]:=s[w[i,1]]+s[w[i,2]]-2*s[f[i]]; if v[i]>maxn then maxn:=v[i]; end; solve; end.