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


    题意:一棵有边权的树上有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.
  • 相关阅读:
    外观模式
    享元模式
    装饰模式
    适配器模式
    组合模式
    典型用户模板与场景
    知识圈APP开发记录(十二)
    知识圈APP开发记录(十一)
    知识圈APP开发记录(十)
    周总结(七)
  • 原文地址:https://www.cnblogs.com/myx12345/p/7475804.html
Copyright © 2020-2023  润新知