2024-10-28-solution-cf733f

CF733F Drivers Dissatisfaction 题解

Yet Another Div2f.

duel 题。

简单题目。首先肯定是只能在一条边上操作的。然后就相当于钦定一条边的最小生成树。相当于减去原最小生成树上 u,vu,v 路径中的最大值。考虑直接 kruskal 重构树解决。

// Problem: Drivers Dissatisfaction
// URL: https://www.luogu.com.cn/problem/CF733F
// Writer: WRuperD
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e18;
const int mininf = 1e9 + 7;
#define int long long
#define pb emplace_back
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
#define put() putchar(' ')
#define endl puts("")
const int MAX = 2e5 + 10;

struct node{
	int u, v, w, w2;
	int id;
}; node edg[MAX];


int psz;
int fa[MAX * 4];
int val[MAX * 4], val2[MAX * 4];

int find(int x){
	if(fa[x] == x)	return x;
	return fa[x] = find(fa[x]);
}

vector <int> g2[MAX * 10];

int fat[MAX * 4], siz[MAX * 4], son[MAX * 4];
int dep[MAX * 4];
void dfs(int u){
	siz[u] = 1;
	for(int v : g2[u]){
		fat[v] = u, dep[v] = dep[u] + 1;
		dfs(v);
		siz[u] += siz[v];
		if(siz[son[u]] < siz[v])	son[u] = v;
	}
}

int top[MAX];

void dfs2(int u, int topu){
	top[u] = topu;
	if(son[u])	dfs2(son[u], topu);
	for(int v : g2[u]){
		if(v != son[u])	dfs2(v, v);
	}
}

int lca(int u, int v){
	while(top[u] != top[v]){
		if(dep[top[u]] < dep[top[v]])	swap(u, v);
		u = fat[top[u]];
	}
	return dep[u] < dep[v] ? u : v;
}
bool cmp(node x, node y){
	if(x.w != y.w){
		return x.w < y.w;
	}
	return x.w2 < y.w2;
}

bool vis[MAX];

void solve(){
	int n = read(), m = read();
	for(int i = 1; i <= m; i++){
		edg[i].w = read();
		edg[i].id = i;
	}	
	for(int i = 1; i <= m; i++){
		edg[i].w2 = read();
	}
	for(int i = 1; i <= m; i++){
		edg[i].u = read(), edg[i].v = read();
	}
	sort(edg + 1, edg + m + 1, cmp);
	for(int i = 1; i <= n; i++)	fa[i] = i;
	psz = n;
	int ans = 0;
	for(int i = 1; i <= m; i++){
		if(find(edg[i].u) == find(edg[i].v))	continue;
		vis[i] = 1;
		ans += edg[i].w;
		g2[++psz].pb(find(edg[i].u));	
		g2[psz].pb(find(edg[i].v));	
		fa[find(edg[i].u)] = fa[find(edg[i].v)] = psz;
		fa[psz] = psz;
		val[psz] = edg[i].w;
		val2[psz] = i;
	}
	int S = read();
	// write(S), endl;
	int rt = find(1);
	dfs(rt);
	dfs2(rt, rt);
	int realans = inf;
	// write(ans), endl;
	int mk = 0;
	for(int i = 1; i <= m; i++){
		int now = ans;
		if(vis[i]){
			// write(edg[i].w), put(), write(edg[i].w2), endl;
			now -= S / edg[i].w2;
			// write(now), endl;
			if(realans > now){
				realans = now;
				mk = i;
			}
			// ans = min(ans, now);
		}else{
			now -= val[lca(edg[i].u, edg[i].v)];
			// write(lca(edge))
			now += edg[i].w;
			now -= S / edg[i].w2;
			// write(now), endl;
			if(realans > now){
				realans = now;
				mk = i;
			}
		}
	}
	write(realans), endl;
	if(vis[mk]){
		for(int i = 1; i <= m; i++){
			if(vis[i]){
			write(edg[i].id), put();
				if(i == mk){
					write(edg[i].w - S / edg[i].w2), endl;
				}else{
					write(edg[i].w), endl;
				}
			}
		}
		return ; 
	}
	vis[val2[lca(edg[mk].u, edg[mk].v)]] = 0;
	for(int i = 1; i <= m; i++){
		if(vis[i]){
			write(edg[i].id), put();
			if(i == mk){
				write(edg[i].w - S / edg[i].w2), endl;
			}else{
				write(edg[i].w), endl;
			}
		}
		if(i == mk){
			write(edg[i].id), put();
			if(i == mk){
				write(edg[i].w - S / edg[i].w2), endl;
			}else{
				write(edg[i].w), endl;
			}
		}
	}
	return ;
}

signed main(){
	int t = 1;
	while(t--)	solve();
	return 0;
}