题目:一个带权连通无向图,给第i条边权值减1需要花费ci元,你一共有S元,求最小生成树。

容易得出钱全部花在一条边上是最优的。

我们先做一遍最小生成树。

然后我们枚举减哪一条边。

如果这条边是树上的,那么直接得出答案。

如果不是,我们可以用这一条边去替换u[i]、v[i]路径之间任意一条。所以我们用倍增(我sb了用的树链剖分)找到路径上最大的那一条替换,计算答案。

最后把这条边放进树里,再求一遍最小生成树就能输出方案了。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define MAX(a,b) a>b?a:b
#define N 210000
#define M 210000
#define mem(a) memset(a,0,sizeof(a))
#define rep(i,n) for (int i=1;i<=(n);i++)
#define LL long long
using namespace std;
int uu,vv,root,ee,rr,ll,_,n,tot,e[M<<],head[N],nex[N<<];
int id,p,q,m,top[N],siz[N],s[N],d[N],w[N],f[N],l[N<<],r[N<<];
LL fuck,a[N<<],orz,sum,S,ans,ma;
bool intree[M];
struct lbz
{
int u,v,d;
LL w,c;
}ed[M];
void add(int u,int v,int c)
{
e[++ee]=v;nex[ee]=head[u];head[u]=ee;
}
void build(int s,int ll,int rr)
{
l[s]=ll;r[s]=rr;
if (ll==rr)
a[s]=;
else
{
int mid=(ll+rr)>>;
build(s<<,ll,mid);
build((s<<)+,mid+,rr);
}
}
void add(int s)
{
if (l[s]==r[s])
a[s]=rr;
else
{
if (r[s<<]>=ll)
add(s<<);
else
add((s<<)+);
a[s]=MAX(a[s<<],a[(s<<)+]);
}
}
void sea(int s)
{
if (l[s]>rr || r[s]<ll)
return;
if (l[s]>=ll&&r[s]<=rr)
ans=MAX(ans,a[s]);
else
{
sea(s<<);
sea((s<<)+);
}
}
void dfs1(int u)
{
int j=head[u];
siz[u]=;
while (j>)
{
if (d[e[j]]==)
{
d[e[j]]=d[u]+;
f[e[j]]=u;
dfs1(e[j]);
if (siz[e[j]]>siz[s[u]])
s[u]=e[j];
siz[u]+=siz[e[j]];
}
j=nex[j];
}
}
void dfs2(int u)
{
int j=head[u];
if (s[u]!=)
{
w[s[u]]=++tot;
top[s[u]]=top[u];
dfs2(s[u]);
}
while (j>)
{
if (e[j]!=s[u]&&e[j]!=f[u])
{
w[e[j]]=++tot;
top[e[j]]=e[j];
dfs2(e[j]);
}
j=nex[j];
}
}
void init()
{
orz=sum;
id=;
mem(f);
}
bool cmp(lbz a,lbz b)
{
return a.w<b.w;
}
int find(int x)
{
if (f[x]==) return x;
f[x]=find(f[x]);
return f[x];
}
int main()
{
scanf("%d%d",&n,&m);
rep(i,m)
scanf("%I64d",&ed[i].w);
rep(i,m)
scanf("%I64d",&ed[i].c);
rep(i,m)
scanf("%d%d",&ed[i].u,&ed[i].v);
scanf("%I64d",&S);
rep(i,m)
ed[i].d=i;
sort(ed+,ed++m,cmp);
rep(i,m)
{
p=find(ed[i].u);
q=find(ed[i].v);
if (p!=q)
{
f[p]=q;
intree[i]=;
sum+=ed[i].w;
}
}
init();
rep(i,m)
if (intree[i]==)
{
add(ed[i].u,ed[i].v,ed[i].w);
add(ed[i].v,ed[i].u,ed[i].w);
}
build(,,n-);
root=;d[root]=;top[root]=root;
dfs1(root);
dfs2(root);
rep(i,m)
{
if (intree[i]==)continue;
if (d[ed[i].u]>d[ed[i].v])
swap(ed[i].u,ed[i].v);
ll=w[ed[i].v];rr=ed[i].w;
add();
}
rep(i,m)
{
if (intree[i]==)
{
fuck=sum-S/ed[i].c;
if (fuck<orz)
{
orz=fuck;
id=i;
}
continue;
}
uu=ed[i].u;vv=ed[i].v;
ma=;
while (top[uu]!=top[vv])
{
if (d[top[uu]]<d[top[vv]])
swap(uu,vv);
ans=;ll=w[top[uu]];rr=w[uu];sea();
ma=MAX(ma,ans);
uu=f[top[uu]];
}
if (uu!=vv)
{
if (d[uu]<d[vv]) swap(uu,vv);
ans=;ll=w[s[vv]];rr=w[uu];sea();
ma=MAX(ma,ans);
}
fuck=sum-ma+ed[i].w-S/ed[i].c;
if (fuck<orz)
{
orz=fuck;
id=i;
}
}
mem(f);mem(intree);
ed[id].w-=S/ed[id].c;
sort(ed+,ed++m,cmp);
rep(i,m)
{
p=find(ed[i].u);
q=find(ed[i].v);
if (p!=q)
{
f[p]=q;
intree[i]=;
}
}
printf("%I64d\n",orz);
rep(i,m)
if (intree[i])
printf("%d %I64d\n",ed[i].d,ed[i].w);
return ; }
# When Who Problem Lang Verdict Time Memory
22090610 2016-11-07 11:28:10 lbz007 F - Drivers Dissatisfaction GNU C++ Accepted 608 ms 34700 KB

最新文章

  1. 浅析:点击父控件时,子控件中的textview自动进入选中状态
  2. WebView返回时设置Title
  3. CSS 文本和表格中文字溢出显示省略号
  4. Linq学习笔记---Linq to Xml操作
  5. [转]Hive/Beeline 使用笔记
  6. linq和EF查询的用法和区分
  7. Android开发之权限列表
  8. forEach遍历对象数组案例
  9. UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类
  10. VI修改文件
  11. Ubuntu操作系统下安装JDK、tomcat、mysql
  12. msgpack库的神奇用法
  13. pytest 15 fixture之autouse=True
  14. TCP/IP学习20180630-数据链路层-router choose
  15. Java 就业班 Web框架
  16. angular 上传图像的使用总结
  17. 基础的shell脚本
  18. idea 配置多个jdk
  19. JQuery中eq()和get()的区别
  20. c++ 类型定义

热门文章

  1. SHELL用法六(Find语句)
  2. inventor卸载/完美解决安装失败/如何彻底卸载清除干净inventor各种残留注册表和文件的方法
  3. Mybatis/ibatis基础知识
  4. C++入门级小算法
  5. 吴裕雄--天生自然 R语言开发学习:中级绘图(续二)
  6. DOS命令编译JAVA程序
  7. 本地开启https服务
  8. Kubelet
  9. Linux 信号介绍
  10. 这个黑科技iPhone8会用吗?人体传送密码解开锁屏