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

【NOIP2015】运输计划(树上差分,二分答案)

时间:2017-09-04 22:43:28      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:方案   sizeof   break   选择   val   for   bool   add   ast   

题意:一棵有边权的树上有m条路径,要求选择一条边使其边权变为0,使得最大路径长度和最小

n,m<=300000

思路:直接求最优方案不可做,但检验对于某一个ans是否能有方案是可行的

取出所有总长度>ans的路径,求它们的交,取交集中长度最大的一条,设值为c[i],总长度最长的设为max

比较max-c[i]与ans的关系即可

路径求交因为是离线的,可以暴力树剖,也可以分类讨论维护路径交

但对于这个离线的问题,可以差分来做

对于路径(a[i],b[i]),设c[i]=lca

分为a[i]到lca,b[i]到lca两条路径 

f[a[i]]++ f[b[i]]++ f[c[i]]=f[c[i]]-2

最后自底向下dfs一遍即可

贴个两年前写的代码

  1 var f:array[1..300000,0..19]of longint;
  2     head,vet,next,dep,fa,val,x,y,z,a,b,r,cnt,size,len,c,dis:array[1..700000]of longint;
  3     n,m,i,left,right,mid,last,tot,tmp,maxw,maxans:longint;
  4 
  5 procedure add(a,b,c:longint);
  6 begin
  7  inc(tot);
  8  next[tot]:=head[a];
  9  vet[tot]:=b;
 10  len[tot]:=c;
 11  head[a]:=tot;
 12 end;
 13 
 14 procedure dfs(u,father:longint);
 15 var e,v,i:longint;
 16 begin
 17  for i:=1 to 19 do
 18  begin
 19   if dep[u]<1<<i then break;
 20   f[u,i]:=f[f[u,i-1],i-1];
 21  end;
 22  size[u]:=1;
 23  e:=head[u];
 24  while e<>0 do
 25  begin
 26   v:=vet[e];
 27   if v<>fa[u] then
 28   begin
 29    f[v,0]:=u;
 30    fa[v]:=u;
 31    dep[v]:=dep[u]+1;
 32    dis[v]:=dis[u]+len[e];
 33    dfs(v,u);
 34    size[u]:=size[u]+size[v];
 35   end;
 36   e:=next[e];
 37  end;
 38 end;
 39 
 40 procedure swap(var x,y:longint);
 41 var t:longint;
 42 begin
 43  t:=x; x:=y; y:=t;
 44 end;
 45 
 46 function lca(x,y:longint):longint;
 47 var i,d:longint;
 48 begin
 49  if dep[x]<dep[y] then swap(x,y);
 50  d:=dep[x]-dep[y];
 51  for i:=0 to 19 do
 52   if d and (1<<i)>0 then x:=f[x,i];
 53  for i:=19 downto 0 do
 54   if f[x,i]<>f[y,i] then
 55   begin
 56    x:=f[x,i]; y:=f[y,i];
 57   end;
 58  if x=y then exit(x);
 59  exit(f[x,0]);
 60 end;
 61 
 62 function max(x,y:longint):longint;
 63 begin
 64  if x>y then exit(x);
 65  exit(y);
 66 end;
 67 
 68 function dfs2(u:longint):longint;
 69 var e,v:longint;
 70 begin
 71  e:=head[u];
 72  while e<>0 do
 73  begin
 74   v:=vet[e];
 75   if v<>fa[u] then cnt[u]:=cnt[u]+dfs2(v);
 76   e:=next[e];
 77  end;
 78  if cnt[u]=tmp then maxw:=max(maxw,val[u]);
 79  exit(cnt[u]);
 80 end;
 81 
 82 function isok(k:longint):boolean;
 83 var i:longint;
 84 begin
 85  maxans:=0; maxw:=0; tmp:=0;
 86  fillchar(cnt,sizeof(cnt),0);
 87  for i:=1 to n do
 88   if c[i]>k then
 89   begin
 90    maxans:=max(maxans,c[i]);
 91    inc(cnt[a[i]]);
 92    inc(cnt[b[i]]);
 93    cnt[r[i]]:=cnt[r[i]]-2;
 94    inc(tmp);
 95   end;
 96 
 97  dfs2(1);
 98  if maxans-maxw<=k then exit(true);
 99  exit(false);
100 end;
101 
102 begin
103 
104  readln(n,m);
105  for i:=1 to n-1 do
106  begin
107   readln(x[i],y[i],z[i]);
108   add(x[i],y[i],z[i]);
109   add(y[i],x[i],z[i]);
110  end;
111  dfs(1,0);
112  for i:=1 to m do
113  begin
114   readln(a[i],b[i]);
115   r[i]:=lca(a[i],b[i]);
116   c[i]:=dis[a[i]]+dis[b[i]]-dis[r[i]]*2;
117  end;
118 
119  for i:=1 to n-1 do
120   if dep[x[i]]>dep[y[i]] then val[x[i]]:=z[i]
121    else val[y[i]]:=z[i];
122 
123  left:=0; right:=50000000;
124  while left<=right do
125  begin
126   mid:=(left+right)>>1;
127   if isok(mid) then begin last:=mid; right:=mid-1; end
128    else left:=mid+1;
129  end;
130  writeln(last);
131 
132 
133 end.

 

【NOIP2015】运输计划(树上差分,二分答案)

标签:方案   sizeof   break   选择   val   for   bool   add   ast   

原文地址:http://www.cnblogs.com/myx12345/p/7475804.html

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