Codeforces Round #378 (Div. 2)

11 篇文章 0 订阅
10 篇文章 0 订阅

题意:

给出一张无向图,每条边有权值,现在可以减小某些边的权值,目的是让这张图的最小生成树权值尽可能小,而将第i条边的权值-1需要花费costi的代价,最多只能花费s的代价,请找出一种方案,使得在这个s的代价内让最小生成树的权值尽可能小,并打印出你选择的边和他们的最终权值,如果有多解,任意输出一种即可


solution:

其实还是可做的。。

先对原图求一个最小生成树,把选择的边拿出来,做成一棵树

题目允许我们修改某些边的权值,那么假设我们拿到了一个最优方案,完全可以让所有修改都发生在其中那条最便宜的边上,,这样总能使得答案至少不会变差

假设我们让所有操作都发生在第i条边上,而我们已经做成了一棵原图最小生成树

把这条新边加入这棵树,得到一个环,环上一定有一条边权值最大,那就不要它,用这条新边,看看答案是否能够更优就好了

啊。。这样做正确性显然。。。。。。。反正是对的,嗯。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn = 2E5 + 20;
typedef long long LL;

struct E{
	int to,w,Num; E(){}
	E(int to,int w,int Num): to(to),w(w),Num(Num){}
};

struct E2{
	int x,y,w,Num; E2(){}
	E2(int x,int y,int w,int Num): x(x),y(y),w(w),Num(Num){}
	bool operator < (const E2 &b) const {return w < b.w;}
}edgs[maxn];

int n,m,s,w[maxn],f[maxn],F[maxn],p1,p2,g,Max,pos,
	L[maxn],fa[maxn][20],c[maxn][20],num[maxn][20];
bool bo[maxn];
LL ans,Ans;

vector <E> v[maxn];

void Dfs(int x,int from)
{
	for (int i = 1; i < 20; i++) {
		fa[x][i] = fa[fa[x][i-1]][i-1];
		if (c[x][i-1] < c[fa[x][i-1]][i-1]) 
			c[x][i] = c[fa[x][i-1]][i-1],num[x][i] = num[fa[x][i-1]][i-1];
		else c[x][i] = c[x][i-1],num[x][i] = num[x][i-1];
	}
	for (int i = 0; i < v[x].size(); i++) {
		E e = v[x][i];
		if (e.to == from) continue;
		L[e.to] = L[x] + 1;
		fa[e.to][0] = x;
		c[e.to][0] = e.w;
		num[e.to][0] = e.Num;
		Dfs(e.to,x);
	}
}

void LCA(int p,int q)
{
	if (L[p] < L[q]) swap(p,q);
	int Log; for (Log = 0; L[p] - (1<<Log) > 0; Log++); --Log;
	for (int j = Log; j >= 0; j--)
		if (L[p] - (1<<j) >= L[q]) {
			if (c[p][j] > Max) 
				Max = c[p][j],pos = num[p][j];
			p = fa[p][j];
		}
	if (p == q) return;
	for (int j = Log; j >= 0; j--)
		if (fa[p][j] != fa[q][j]) {
			if (c[p][j] > Max) 
				Max = c[p][j],pos = num[p][j];
			if (c[q][j] > Max) 
				Max = c[q][j],pos = num[q][j];
			p = fa[p][j]; q = fa[q][j];
		}
	if (c[p][0] > Max) 
		Max = c[p][0],pos = num[p][0];
	if (c[q][0] > Max) 
		Max = c[q][0],pos = num[q][0];
}

int getfa(int k) {return k == F[k]?k:F[k] = getfa(F[k]);}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n >> m;
	for (int i = 1; i <= n; i++) F[i] = i;
	for (int i = 1; i <= m; i++) scanf("%d",&w[i]);
	for (int i = 1; i <= m; i++) scanf("%d",&f[i]);
	for (int i = 1; i <= m; i++) {
		int x,y; scanf("%d%d",&x,&y);
		edgs[i] = E2(x,y,w[i],i);
	}
	sort(edgs + 1,edgs + m + 1);
	for (int i = 1; i <= m; i++) {
		int fx = getfa(edgs[i].x);
		int fy = getfa(edgs[i].y);
		if (fx == fy) continue;
		F[fx] = fy; bo[i] = 1;
		ans += 1LL*edgs[i].w;
		v[edgs[i].x].push_back(E(edgs[i].y,edgs[i].w,edgs[i].Num));
		v[edgs[i].y].push_back(E(edgs[i].x,edgs[i].w,edgs[i].Num));
	}
	L[1] = 0; Dfs(1,0); Ans = ans; cin >> s;
	for (int i = 1; i <= m; i++) {
		int G = edgs[i].w - s/f[edgs[i].Num];
		Max = 0; LCA(edgs[i].x,edgs[i].y);
		if (ans > Ans + 1LL*(G - Max)) {
			ans = Ans + 1LL*(G - Max);
			g = G; p1 = pos; p2 = edgs[i].Num;
		}
	}
	
	cout << ans << endl;
	if (p2) cout << p2 << ' ' << g << endl;
	for (int i = 1; i <= m; i++)
		if (bo[i] && edgs[i].Num != p1) 
			printf("%d %d\n",edgs[i].Num,edgs[i].w);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值