码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

时间:2016-08-10 00:44:31      阅读:708      评论:0      收藏:0      [点我收藏+]

标签:

                                                    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.
View Code

 

BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

标签:

原文地址:http://www.cnblogs.com/qtyytq/p/5755055.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!