【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.
时间: 2024-12-28 16:11:37

【NOIP2015】运输计划(树上差分,二分答案)的相关文章

Noip2015 运输计划 树上差分 二分答案

Code: #include<cstring> #include<cstdio> #include<algorithm> #include<string> using namespace std; void setIO(string a){freopen((a+".in").c_str(),"r",stdin);} #define maxn 300090 #define logn 20 int head[maxn],t

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们

[NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去.显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰. 为了鼓励科技创新,L国国王同意小P的物流

【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 703  Solved: 461[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

NOIP2015 运输计划(二分+LCA+差分)

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 208[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

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

NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰.为了鼓励科技创新, L

树链剖分-Hello!链剖-[NOIP2015]运输计划-[填坑]

This article is made by Jason-Cow.Welcome to reprint.But please post the writer's address. http://www.cnblogs.com/JasonCow/ [NOIP2015]运输计划    Hello!链剖.你好吗? 题意: 给出一棵n个节点的带权树,m对树上点对 现在允许删除一条边,(权值修改为0) 输出: 最小化的点对间最大距离 1.链剖 2.树上差分 3.二分 链剖我就不多说了,就是两dfs 注意

AC日记——[NOIP2015]运输计划 cogs 2109

[NOIP2015] 运输计划 思路: 树剖+二分: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 300005 #define INF 0x7fffffff int n,deep[maxn],dis[maxn],dis_[maxn],f[maxn],top[maxn]; i

数据结构(树链剖分):COGS 2109. [NOIP2015] 运输计划

2109. [NOIP2015] 运输计划 ★★★   输入文件:transport.in   输出文件:transport.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物 流飞船需要从 ui 号星球沿最快的宇航路径飞行到 v

BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)

题意:中文题. 析:首先二分是很容易想出来的,然后主要是判断这个解合不合法,先二分答案 mid,因为有 m 个计划,所以只要添加虫洞的肯定是所有的时间长于 mid 的计划 中,也就是是那些的共同边,这个就可以用树上差分来做了,假设 s 到 t,那么让in[s]++,in[t]++,in[lca(s, t)] -= 2,其中in 表示的是 该结点与其父结点的边的计数,最后再跑一次dfs,把所有的权值都累加上去,这样就能知道哪些是共同的边了. 代码如下: #pragma comment(linker