题意:给出一个图,每条边有权值和花费c,每次花费c能使的权值-1。给出一个预算,求减完权值后的一个最小生成树。

思路:感谢CC大神

有这样一个结论:最佳方案里必定存在一种,预算全部花费全部分配在一条边上。证明显然,对于任意一组解,都可以在内部再分配预算使总费用更小或不变。

于是先求出原图的最小生成树,枚举每条边。

对于在生成树中的,判断使这条边减费是否更优。

不在生成树上的,找出树上从x[i]到y[i]的路径(唯一)上a[i]最大的边,判断删除那条边并加入减费后的(x[i],y[i])是否更优。

 type yjs=record
a:longint;
s:int64;
end;
var f,q,g:array[..,..]of longint;
head,vet,next,len,num,a,b,c,x,y,dep,fa,inq,ya,yb:array[..]of longint;
hth,mst,s:int64;
tot,n,m,i,del,k,tx,ty:longint;
t:yjs; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=a[(l+r)>>];
repeat
while mid>a[i] do inc(i);
while mid<a[j] do dec(j);
if i<=j then
begin
swap(a[i],a[j]); swap(b[i],b[j]); swap(c[i],c[j]);
swap(x[i],x[j]); swap(y[i],y[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; procedure add(a,b,c,d:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
num[tot]:=d;
head[a]:=tot;
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:=q[x,i];
for i:= downto do
if q[x,i]<>q[y,i] then
begin
x:=q[x,i]; y:=q[y,i];
end;
if x=y then exit(x);
exit(q[x,]);
end; function clac(x,y:longint):yjs;
var i,d:longint;
cc:yjs;
begin
if dep[x]<dep[y] then swap(x,y);
d:=dep[x]-dep[y];
cc.a:=; cc.s:=-maxlongint;
for i:= downto do
if d and (<<i)> then
begin
if f[x,i]>cc.s then
begin
cc.a:=g[x,i];
cc.s:=f[x,i];
end;
x:=q[x,i];
end;
exit(cc);
end; function ask(x,y:longint):yjs;
var t:longint;
t1,t2:yjs;
begin
t:=lca(x,y);
t1:=clac(x,t);
t2:=clac(y,t);
if t1.s>t2.s then exit(t1);
exit(t2);
end; function find(k:longint):longint;
begin
if fa[k]<>k then fa[k]:=find(fa[k]);
find:=fa[k];
end; procedure dfs(u,pre:longint);
var e,v,i:longint;
begin
for i:= to do
begin
if dep[u]<(<<i) then break;
q[u,i]:=q[q[u,i-],i-];
if f[u,i-]<f[q[u,i-],i-] then
begin
f[u,i]:=f[q[u,i-],i-];
g[u,i]:=g[q[u,i-],i-];
end
else
begin
f[u,i]:=f[u,i-];
g[u,i]:=g[u,i-];
end;
end;
e:=head[u];
while e<> do
begin
v:=vet[e];
if v<>pre then
begin
dep[v]:=dep[u]+;
f[v,]:=len[e];
q[v,]:=u;
g[v,]:=num[e];
dfs(v,u);
end;
e:=next[e];
end;
end; begin readln(n,m);
for i:= to m do read(a[i]);
for i:= to m do read(b[i]);
for i:= to m do c[i]:=i;
for i:= to m do readln(x[i],y[i]);
readln(s);
ya:=a; yb:=b;
qsort(,m);
for i:= to n do fa[i]:=i;
for i:= to m do
begin
tx:=find(x[i]); ty:=find(y[i]);
if tx<>ty then
begin
fa[ty]:=tx;
hth:=hth+a[i];
inq[c[i]]:=;
add(x[i],y[i],a[i],c[i]);
add(y[i],x[i],a[i],c[i]);
end;
end;
dfs(,-);
mst:=hth;
for i:= to m do
if inq[c[i]]= then
begin
if mst-s div b[i]<hth then
begin
hth:=mst-s div b[i];
k:=c[i];
end;
end
else
begin
t:=ask(x[i],y[i]);
if mst-ya[t.a]+a[i]-s div b[i]<hth then
begin
hth:=mst-ya[t.a]+a[i]-s div b[i];
k:=c[i];
del:=t.a;
end;
end;
writeln(hth);
for i:= to m do
begin
if i=del then continue;
if i=k then begin writeln(i,' ',ya[i]-s div yb[i]); continue; end;
if inq[i]= then writeln(i,' ',ya[i]);
end; end.

最新文章

  1. 关于android中调用系统拍照,返回图片是旋转90度
  2. js的Promise学习笔记(1)
  3. Oracle 游标使用全解
  4. 千万级SQL Server数据库表分区的实现
  5. [原创]可动态显示圆形图像或圆形文字的AvatarImageView
  6. Direct2D开发:纹理混合
  7. flask中文问题
  8. ReactNative 踩坑小计
  9. Android 开发性能优化之SparseArray(一)
  10. 学习基于OpenGL的CAD程序的开发计划(一)
  11. 集合如何判断null
  12. SQLServer数据库误删数据找回
  13. 1.Redis 的安装
  14. ucos-ii的任务调度机制
  15. 美团、java后台实习、面经
  16. redis底层设计(一)——内部数据结构
  17. L317 电子烟
  18. No setter found for property &#39;cronExpression&#39; in class &#39;org.springframework.scheduling.quartz.CronTriggerBean&#39;
  19. ubuntu14安装TensorFlow
  20. 【BZOJ 4819】 4819: [Sdoi2017]新生舞会 (0-1分数规划、二分+KM)

热门文章

  1. 【树形dp】bzoj4726: [POI2017]Sabota?
  2. token_get_all()函数
  3. springBoot 集成swagger2.9.2
  4. 示例vue 的keep-alive缓存功能的实现
  5. python并发编程之进程2(管道,事件,信号量,进程池)
  6. python3中urllib库的request模块详解
  7. LeetCode(307) Range Sum Query - Mutable
  8. TCP的三次握手和四次握手
  9. mysql PacketTooBigException 的处理方式
  10. cache共享问题