【codeforces 733F】 Drivers Dissatisfaction

news/2024/7/7 14:52:58

http://codeforces.com/problemset/problem/733/F (题目链接)

题意

  给出一张n个点的无向图,每一条变有两个特征值:${w,c}$;分别表示这条边的权值为${w}$,每将这条边的权值减小1需要充${c}$元钱。初始时有${S}$元钱,你可以对任意边充钱使得它的权值${w}$减少,甚至减成负数。现在需要你选出若干条边,使得所有的点都联通并且这些边的权值和在“充了钱”之后最小。

Solution

  codeforces上的题目真是良心题。

  想一想,假设我们已经选出了一些边,如果我们“充钱”,反正充哪条边都是只能使最终答案减小1,不如就抓着其中一条${c}$最小的边一通狂充,不充钱还想跟我玩?于是我们就很容易得到一个初始想法:跑一遍关于${w}$的最小生成树,然后狂减${c}$最小的边,得到一个初始答案${ans}$。

  考虑这样一种情况:可能存在一条不在最小生成树的边,但是它的${c}$比最小生成树中的边的${c}$都要小,我们可以将它选入答案并通过对它“充钱”,使答案更优。

  这样的情况怎么处理呢?我们枚举每一条不在最小生成树中并且${c}$符合要求的边,尝试将它加入生成树中。加入一条边${(u,v)}$,那么必定要删掉树上一条边,那么删去的这条边一定是树上${u,v}$间${w}$最大的一条边,此时我们不用考虑树中的边的${c}$,因为如果我们要“充钱”一定是对新加入的这条边充,如果最后剩下的钱小于新加入这条边的${c}$,那么显然剩下的钱已经不能再做出贡献了。

  那么现在问题就是如何快速查询树上两点间的最长边,是不是很熟悉,没错就是NOIP2013货车运输,直接树上倍增即可。

细节

  记得开long long。然后方案的统计有点麻烦,注意不要写错,Wa on test 100,莫名其妙过了前面99个点,这是要FST的节奏啊→_→。

代码

// codeforces 733F
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define MOD 99999997
#define inf 2000000000
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=200010;
struct edge {int to,next,w,id;}e[maxn<<1];
struct data {int u,v,w,c,id;}a[maxn];
int f[maxn],head[maxn],fa[maxn][30],bin[30],d[maxn][30],deep[maxn],b[maxn];
int cnt,S,n,m,prt[maxn],pp[maxn];

bool cmp(data a,data b) {
	return a.w<b.w;
}
int maxw(int x,int y) {
	return a[x].w<a[y].w ? y : x;
}
int find(int x) {
	return x==f[x] ? x : f[x]=find(f[x]);
}
void link(int u,int v,int w) {
	e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
	e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w;
}
void dfs(int x) {
	for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=1;i<=20;i++) d[x][i]=maxw(d[x][i-1],d[fa[x][i-1]][i-1]);
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
			deep[e[i].to]=deep[x]+1;
			d[e[i].to][0]=e[i].w;
			fa[e[i].to][0]=x;
			dfs(e[i].to);
		}
}
int lca(int x,int y) {
	if (deep[x]<deep[y]) swap(x,y);
	int t=deep[x]-deep[y];
	for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
	for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return x==y ? x : fa[x][0];
}
int query(int x,int f) {
	int t=deep[x]-deep[f];
	int res=0;
	for (int i=0;bin[i]<=t;i++) if (bin[i]&t) res=maxw(res,d[x][i]),x=fa[x][i];
	return res;
}
int main() {
	bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++) scanf("%d",&a[i].w);
	for (int i=1;i<=m;i++) scanf("%d",&a[i].c);
	for (int i=1;i<=m;i++) scanf("%d%d",&a[i].u,&a[i].v),a[i].id=i;
	scanf("%d",&S);
	sort(a+1,a+1+m,cmp);
	for (int i=1;i<=n;i++) f[i]=i;
	int C=inf;
	LL ans=0,tot=0;int num=0,dl=0;
	for (int i=1;i<=m;i++) {
		int r1=find(a[i].u),r2=find(a[i].v);
		if (r1!=r2) {
			link(a[i].u,a[i].v,i);
			f[r1]=r2;
			b[i]=1;
			tot+=(LL)a[i].w;
			if (a[i].c<C) C=a[i].c,num=i;
		}
	}
	ans=tot-S/C;
	dfs(1);
	for (int i=1;i<=m;i++) if (a[i].c<C) {
			int ff=lca(a[i].u,a[i].v);
			int x=maxw(query(a[i].u,ff),query(a[i].v,ff));
			LL tmp=(LL)tot-a[x].w+a[i].w-S/a[i].c;
			if (ans>tmp) {
				ans=tmp;b[dl]=1;b[num]=0;b[dl=x]=0;num=i;b[i]=1;}
		}
	printf("%lld\n",ans);
	for (int i=1;i<=m;i++) if (b[i]) {
			int x=num==i ? S/a[i].c : 0;
			prt[a[i].id]=a[i].w-x;
			pp[a[i].id]=1;
		}
	for (int i=1;i<=m;i++) if (pp[i]) printf("%d %d\n",i,prt[i]);
	return 0;
}

  

转载于:https://www.cnblogs.com/MashiroSky/p/6027250.html


http://www.niftyadmin.cn/n/664535.html

相关文章

Java虚拟机(二)对象的创建与OOP-Klass模型

相关文章 Java虚拟机系列 前言 在前一篇文章中我们学习了Java虚拟机的结构原理与运行时数据区域&#xff0c;那么我们大概知道了Java虚拟机的内存的概况&#xff0c;那么内存中的数据是如何创建和访问的呢&#xff1f;这篇文章会给你答案。 1.对象的创建 对象的创建通常是通过…

IIS http 错误 401.3 - unauthorized

iis http 错误 401.3 - unauthorized 向物理目录添加iis_iusrs用户权限。转载于:https://www.cnblogs.com/zhanqun/p/5508954.html

Python 2.5 Quick Reference

Python 2.5 Quick Reference 收藏 <script type"text/javascript"> document.body.oncopy function() { if (window.clipboardData) { setTimeout(function() { var text clipboardData.getData(&quot;text&quot;); if (text &amp;&amp; t…

关于离职和领导交流完毕的感受

上回和段总聊了一下&#xff0c;聊完之后我真的是又坚定了离开的想法。我说我要离开时因为我的自学能力在逐步的下降&#xff0c;我自己学些的动力被一点一点的消磨掉了。早上我卡着点来是因为李萍老师&#xff0c;原因就是我不想听他放那些乱七八糟的音乐&#xff08;我认为这…

dell n2000 组播抑制

dell n2000 组播抑制 http://en.community.dell.com/support-forums/network-switches/f/866/t/19677497http://en.community.dell.com/support-forums/network-switches/f/866/t/19650967http://www.dell.com/Support/Article/us/en/04/SLN295739 # vlan20是组播vlan, 192.168…

Java虚拟机(三)垃圾标记算法与Java对象的生命周期

相关文章 Java虚拟机系列 前言 这一节我们来简单的介绍垃圾收集器&#xff0c;并学习垃圾标记的算法&#xff1a;引用计数算法和根搜索算法&#xff0c;为了更好的理解根搜索算法&#xff0c;会在文章的最后介绍Java对象在虚拟机中的生命周期。 1.垃圾收集器概述 垃圾收集器&a…

在ubuntu下配置apache运行python脚本

常用的简单命令 sudo apt-get remove --purge apache apache2 (彻底删除) sudo /etc/init.d/apache2 restart sudo /etc/init.d/apache2 start sudo /etc/init.d/apache2 stop sudo makedir /home/htdocs sudo chmod 777 /home/htdocs 生成网站目录&#xff0c;并修改权限 ubun…

bzoj3012[Usaco2012 Dec]First! 一号单词

题目链接&#xff1a;http://www.lydsy.com/JudgeOnline/problem.php?id3012 题目大意&#xff1a; 给n个字符串&#xff0c;问如果重新定义英文字符的顺序&#xff08;就是重定义字典序&#xff09;&#xff0c;有哪些单词可能排在字典的第一名 举例来说&#xff0c;假设有四…