Codeforces Round #378 (Div. 2)F
2024-10-08 22:33:10
题目:一个带权连通无向图,给第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 |
最新文章
- 浅析:点击父控件时,子控件中的textview自动进入选中状态
- WebView返回时设置Title
- CSS 文本和表格中文字溢出显示省略号
- Linq学习笔记---Linq to Xml操作
- [转]Hive/Beeline 使用笔记
- linq和EF查询的用法和区分
- Android开发之权限列表
- forEach遍历对象数组案例
- UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类
- VI修改文件
- Ubuntu操作系统下安装JDK、tomcat、mysql
- msgpack库的神奇用法
- pytest 15 fixture之autouse=True
- TCP/IP学习20180630-数据链路层-router choose
- Java 就业班 Web框架
- angular 上传图像的使用总结
- 基础的shell脚本
- idea 配置多个jdk
- JQuery中eq()和get()的区别
- c++ 类型定义