【NOIP2015】运输计划(树上差分,二分答案)
2024-09-08 01:34:38
题意:一棵有边权的树上有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一遍即可
贴个两年前写的代码
var f:array[..,..]of longint;
head,vet,next,dep,fa,val,x,y,z,a,b,r,cnt,size,len,c,dis:array[..]of longint;
n,m,i,left,right,mid,last,tot,tmp,maxw,maxans:longint; procedure add(a,b,c:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
head[a]:=tot;
end; procedure dfs(u,father:longint);
var e,v,i:longint;
begin
for i:= to do
begin
if dep[u]<<<i then break;
f[u,i]:=f[f[u,i-],i-];
end;
size[u]:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if v<>fa[u] then
begin
f[v,]:=u;
fa[v]:=u;
dep[v]:=dep[u]+;
dis[v]:=dis[u]+len[e];
dfs(v,u);
size[u]:=size[u]+size[v];
end;
e:=next[e];
end;
end; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; function lca(x,y:longint):longint;
var i,d:longint;
begin
if dep[x]<dep[y] then swap(x,y);
d:=dep[x]-dep[y];
for i:= to do
if d and (<<i)> then x:=f[x,i];
for i:= downto do
if f[x,i]<>f[y,i] then
begin
x:=f[x,i]; y:=f[y,i];
end;
if x=y then exit(x);
exit(f[x,]);
end; function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end; function dfs2(u:longint):longint;
var e,v:longint;
begin
e:=head[u];
while e<> do
begin
v:=vet[e];
if v<>fa[u] then cnt[u]:=cnt[u]+dfs2(v);
e:=next[e];
end;
if cnt[u]=tmp then maxw:=max(maxw,val[u]);
exit(cnt[u]);
end; function isok(k:longint):boolean;
var i:longint;
begin
maxans:=; maxw:=; tmp:=;
fillchar(cnt,sizeof(cnt),);
for i:= to n do
if c[i]>k then
begin
maxans:=max(maxans,c[i]);
inc(cnt[a[i]]);
inc(cnt[b[i]]);
cnt[r[i]]:=cnt[r[i]]-;
inc(tmp);
end; dfs2();
if maxans-maxw<=k then exit(true);
exit(false);
end; begin readln(n,m);
for i:= to n- do
begin
readln(x[i],y[i],z[i]);
add(x[i],y[i],z[i]);
add(y[i],x[i],z[i]);
end;
dfs(,);
for i:= to m do
begin
readln(a[i],b[i]);
r[i]:=lca(a[i],b[i]);
c[i]:=dis[a[i]]+dis[b[i]]-dis[r[i]]*;
end; for i:= to n- do
if dep[x[i]]>dep[y[i]] then val[x[i]]:=z[i]
else val[y[i]]:=z[i]; left:=; right:=;
while left<=right do
begin
mid:=(left+right)>>;
if isok(mid) then begin last:=mid; right:=mid-; end
else left:=mid+;
end;
writeln(last); end.
最新文章
- SFC中的故障管理
- iOS--NSTimer设置定时器的两种方法
- c#根据公式进行自动计算 四个5加减乘除=4
- Java Data Type
- Unity2D多分辨率屏幕适配方案(转载)
- 使用Unity3D自带动画系统制作下雨效果
- OpenERP里面继承的用法
- 如何实现TWaver 3D颜色渐变
- js获取input上传文件名和后缀
- 使用github 的相关博客
- 图数据库-Neo4j使用
- python的函数学习2
- Java虚拟机JVM相关知识整理
- SSM-动态SQL
- Ymodem协议(参考STM32)
- mysql外键的三种关系
- 如何在Windows环境下安装JDK
- 8 -- 深入使用Spring -- 3...1 Resource实现类FileSystemResource
- 常用算法1 - 快速排序 &; 二分查找
- MySQL(二)索引背后的数据结构及算法原理