扯在前面

人生第一道黑(>▽< )。

那天听了老师讲图论讲了这道题,发现这道黑题并不是很黑于是就做了做,在同机房dalao的帮助下三个小时做完(太菜了),于是来发篇题解。


正文

题意

给出一张 n 个点 m 条边的无向图,每条边(ai,bi)有一个权值 wi 和费用 ci,表示这条边 每降低 1 的权值需要 ci 的花费。现在一共有 S 费用可以用来降低某些边的权值(可以降到 负数),求图中的一棵权值和最小的生成树并输出方案


分析

本题就是一个求最小生成树加不定边的题目,而且输出多了个方案

题目中信息很多,在这里先总结一下:

  1. 最多降低权值为 S / ci;
  2. 既然你可以用 S 费用来降低 S / ci 的权值,而且可以降到负数,本题又是求最小生成树,那就一直降一条边就好了(保证降完后本条边是在生成树里的);
  3. 他要求输出方案,就需要开数组或结构体来存储树上的是第几条边以及他的权值

好像就这么点信息也不是很多

那么我们想想该怎么做

  • 我们知道,本题肯定是先求最小生成树,然后再枚举边看是否替换并比较最优方案;
  • 枚举边有两种情况,第一是已经在生成树上的边,既然已经在树上,那么答案就直接把最小生成树权值和减去降低的权值拿来比较就好了
  • 另一方面,最多减低 S / ci 的权值,那 ci 肯定越小越好,所以在树内的边我们就降低 c 最小的那一条
  • 枚举数外的边时,我们要看加入当前边后是否为环(肯定是),把这条边与环上最大的树边比较,如果树边更大就减去这条树边(这个思路是不是有些熟悉)
  • 当不用换边时,就直接输出原树的信息就好了

贴码

做的时候没写注释,但是很好理解,就是lca板子加编号和边权的存储,最后打个标记看是否换边

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<algorithm>
#define maxn 200005
#define INF 1000000000000000000 using namespace std; int n,m;
long long f[maxn][26],depth[maxn];
long long tot,head[maxn*4],fa[maxn],S,ans,num,cnt,sum,flag,lkp,fjh;
bool vis[maxn*2],v[maxn*2]; struct node{
long long dis,c,fr,to,bh,nxt;
}a[maxn*4],e[maxn*4]; struct ma{
long long dis,bh;
}maxi[maxn][26]; inline void add(long long fr,long long to,long long dis,long long c,long long bh){
e[++tot].to=to;
e[tot].fr=fr;
e[tot].dis=dis;
e[tot].bh=bh;
e[tot].c=c;
e[tot].nxt=head[fr];
head[fr]=tot;
} inline long long Getf(long long x){
if(fa[x]==x) return x;
return fa[x]=Getf(fa[x]);
} inline void hb(long long x,long long y){
x=Getf(x);
y=Getf(y);
if(x!=y) fa[y]=x;
} inline bool pd(long long x,long long y){
x=Getf(x);
y=Getf(y);
if(x==y) return true;
return false;
} inline void dfs(long long now,long long p){
f[now][0]=p;
for(long long i=head[now];i;i=e[i].nxt){
long long to=e[i].to;
if(to==f[now][0]) continue;
depth[to]=depth[now]+1ll;
maxi[to][0].dis=e[i].dis;
maxi[to][0].bh=e[i].bh;
dfs(to,now);
}
} inline void caq(){
for(int i=1;i<=25;++i)
for(int j=1;j<=n;++j){
f[j][i]=f[f[j][i-1]][i-1];//
// maxi[j][i]=max(maxi[j][i-1],maxi[f[j][i-1]][i-1]);
// mini[j][i]=max(mini[j][i-1],mini[f[j][i-1]][i-1]);
if(maxi[j][i-1].dis>maxi[f[j][i-1]][i-1].dis){
maxi[j][i].dis=maxi[j][i-1].dis;
maxi[j][i].bh=maxi[j][i-1].bh;
}
else{
maxi[j][i].dis=maxi[f[j][i-1]][i-1].dis;
maxi[j][i].bh=maxi[f[j][i-1]][i-1].bh;
}
}
} inline long long lca(long long x,long long y){
if(depth[x]<depth[y]) swap(x,y);
// while(depth[x]>depth[y])
// x=f[x][lg[depth[x]-depth[y]]-1];
for(int i=25;i>=0;--i)
if(depth[f[x][i]]>=depth[y])
x=f[x][i];
if(x==y) return x;
for(int i=25;i>=0;--i)
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
return f[x][0];
} inline ma get_max(long long u,long long v)
{
ma Ans;
Ans.bh=-1;
Ans.dis=-INF;
for(int i=25;i>=0;--i){
if(depth[f[u][i]]>=depth[v]){
if(Ans.dis<maxi[u][i].dis){
Ans.dis=maxi[u][i].dis;
Ans.bh=maxi[u][i].bh;
}
u=f[u][i];
}
}
return Ans;
} inline long long cmp(node a,node b){
return a.dis<b.dis;
} int main(){
cin>>n;cin>>m; for(int i=1;i<=m;i++) cin>>a[i].dis;
for(int i=1;i<=m;i++) cin>>a[i].c;
for(int i=1;i<=m;i++){
cin>>a[i].fr;
cin>>a[i].to;
a[i].bh=i;
}
cin>>S; for(int i=1;i<=n;i++) fa[i]=i; sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++){
if(!pd(a[i].fr,a[i].to)){
hb(a[i].fr,a[i].to);
add(a[i].fr,a[i].to,a[i].dis,a[i].c,i);
add(a[i].to,a[i].fr,a[i].dis,a[i].c,i);
sum+=a[i].dis;
vis[i]=1;
v[i]=1;
}
} // sort(e+1,e+m+1,cnp); depth[1] = 1;
maxi[1][0].dis = -INF;
maxi[1][0].bh = e[1].bh; dfs(1,1);
caq(); cnt=INF;
for(long long i=1;i<=m;i++){
long long ww=S/a[i].c;
if(vis[i]){
if(cnt>sum-ww){
flag=i;
}
cnt=min(sum-ww,cnt);
}
else{
long long fr=a[i].fr;
long long to=a[i].to;
long long lcaa=lca(fr,to);
ma maxu=get_max(fr,lcaa);
ma maxv=get_max(to,lcaa);
if(maxu.dis>maxv.dis){
if(cnt>sum-maxu.dis+a[i].dis-ww){
cnt=sum-maxu.dis+a[i].dis-ww;
v[lkp]=0;
v[fjh]=1;
v[i]=1;
v[maxu.bh]=0;
lkp=i;
fjh=maxu.bh;
flag=i;
}
}
else{
if(cnt>sum-maxv.dis+a[i].dis-ww){
cnt=sum-maxv.dis+a[i].dis-ww;
v[lkp]=0;
v[fjh]=1;
v[i]=1;
v[maxv.bh]=0;
lkp=i;
fjh=maxv.bh;
flag=i;
}
}
}
// cout<<ww<<" ";
}
if(flag)
a[flag].dis=a[flag].dis-(S/a[flag].c);
printf("%lld\n",cnt);
// cout<<flag<<" ";
// cout<<S/a[flag].c<<endl;
for(int i=1;i<=m;i++)
if(v[i]) printf("%lld %lld\n",a[i].bh,a[i].dis);
return 0;
}

第一次A黑可能比较鸡冻,如果有什么不对的地方请及时告知我

CF733F的更多相关文章

  1. CF733F Drivers Dissatisfaction【链剖】【最小生成树应用】

    F. Drivers Dissatisfaction time limit per test 4 seconds memory limit per test 256 megabytes input s ...

  2. 【CF733F】Drivers Dissatisfaction(最小瓶颈生成树,倍增)

    题意:给出一个图,每条边有权值和花费c,每次花费c能使的权值-1.给出一个预算,求减完权值后的一个最小生成树. 思路:感谢CC大神 有这样一个结论:最佳方案里必定存在一种,预算全部花费全部分配在一条边 ...

  3. 我的刷题单(8/37)(dalao珂来享受切题的快感

    P2324 [SCOI2005]骑士精神 CF724B Batch Sort CF460C Present CF482A Diverse Permutation CF425A Sereja and S ...

随机推荐

  1. maven打包,跳过生成javadoc

    有时候由于代码中注释错误(比如方法参数)或者maven javadoc插件版本有问题,导致打包报错,而我们着急打包验证问题,没有时间一一修改错误,这时候可以先跳过生成javadoc,继续下一步工作. ...

  2. Base 128 Varints 编码(压缩算法)

    Base 128 Varint可以说是一种编码方式,也可以说是一种压缩算法.这种压缩算法是用来压缩数字的传输的,压缩的依据是基于一个现实:越小的数字,越经常使用 我们来看看一个例子: 如果我们要网络传 ...

  3. 如何根据角色批量激活SAP Fiori服务

    我们知道Fiori的角色跟ERP的角色是不通用的,即使你的账号有SAP_ALL的权限,但打开Fiori的时候一样是空的一片: 只有给账号加上fiori需要的角色,并激活相关服务才能用fiori app ...

  4. [ABP教程]第三章 创建、更新和删除图书

    Web应用程序开发教程 - 第三章: 创建,更新和删除图书 关于本教程 在本系列教程中, 你将构建一个名为 Acme.BookStore 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以 ...

  5. Head First 设计模式 —— 11. 组合 (Composite) 模式

    思考题 我们不仅仅要支持多个菜单,升值还要支持菜单中的菜单.你如何处理这个新的设计需求? P355 [提示]在我们的新设计中,真正需要以下三点: P354 我们需要某种属性结构,可以容纳菜单.子菜单和 ...

  6. 【JavaWeb】Tomcat 使用

    Tomcat 使用 基础概念 JavaWeb: JavaWeb:所有通过 Java 语言编写可以通过浏览器访问的程序的总称,它是是基于请求和响应来开发的: 请求:客户端给服务器发送数据,即 Reque ...

  7. maven 的安装与配置详细步骤

    1. 直接搜索maven 2. 进入后点击download界面,这时出现的是当前最新版本, 当然还有以前的版本可供下载 3. 下载解压到你指定的目录后,需要配置一下环境变量. a. 右键此电脑点击属性 ...

  8. 一文带你学会AQS和并发工具类的关系

    1. 存在的意义   AQS(AbstractQueuedSynchronizer)是JAVA中众多锁以及并发工具的基础,其底层采用乐观锁,大量使用了CAS操作, 并且在冲突时,采用自旋方式重试,以实 ...

  9. Loadrunner与kylinPET的能力对比测试--web动态请求

    概述 在<性能测试工具选择策略--仿真度对比测评分析报告>一文详细分析了使用相同的web页面,分别使用LoadRunner,Jmeter,kylinTOP工具进行录制脚本并执行得出在静态请 ...

  10. PC个人隐私保护小方法

    前言 近期爆出了腾讯读取用户浏览器浏览记录的消息.话不过说直接上图,懂的自然懂. 网上也有详细的分析文章,不管它读取后用来做什么,在你不知情的情况下读取了你的浏览器浏览记录,你说气不气. 虽然在整体大 ...