P4180 [BJWC2010]严格次小生成树

传送门
如题,严格次小生成树

分析

对于 K r u s k a l Kruskal Kruskal 执行过程中
先构造最小生成树,然后再贪心的删边
剩下没有参与构造生成树的边,对于边的两个端点
用这条边(记为 A A A边),替换生成树两个端点路径上面的一条边(记为 B B B边)
严格次小, A A A 边一定严格 大于 B B B
我们要求的是对于每条能够替换的边, v ( A ) − v ( B ) v(A)-v(B) v(A)v(B)最小即可

倍增维护生成树链上边的最大值和次大值,按照上面的规则尝试替换边

代码

//P4180
/*
  @Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;

int head[MAX_N];
int tot = 0;
struct Edge {
	int to, nxt, w;
}edge[MAX_N];

void addEdge(int u, int v, int w) {
	edge[tot].nxt = head[u];
	edge[tot].to = v;
	edge[tot].w = w;
	head[u] = tot++;
	edge[tot].nxt = head[v];
	edge[tot].to = u;
	edge[tot].w = w;
	head[v] = tot++;
}

bool use[MAX_N];
struct Node {
	int x, y, w;
}node[MAX_N];

int father[MAX_N];
int find(int x) {
	return x == father[x] ? x : father[x] = find(father[x]);
}

int dep[MAX_N];
int parent[MAX_N][22];
int maxx[MAX_N][22];
int maxx2[MAX_N][22];

void dfs(int u, int from) {
	dep[u] = dep[from] + 1;
	parent[u][0] = from;
	for (int i = 1; i <= 20; ++i) {
		parent[u][i] = parent[parent[u][i-1]][i-1];
		maxx[u][i] = max(maxx[parent[u][i-1]][i-1], maxx[u][i-1]);
		maxx2[u][i] = max(maxx2[parent[u][i-1]][i-1], maxx2[u][i-1]);
		if (maxx[parent[u][i-1]][i-1] != maxx[u][i-1]) {
			maxx2[u][i] = max(maxx2[u][i], min(maxx[parent[u][i-1]][i-1], maxx[u][i-1]));
		}
	}
	
	int v;
	for (int i = head[u];~i;i=edge[i].nxt) {
		if ((v=edge[i].to) == from) continue;
		maxx[v][0] = edge[i].w;
		maxx2[v][0] = 0;
		dfs(v, u);
	}
}

int LCA(int x, int y) {
	if (dep[x] < dep[y]) swap(x, y);
	
	for (int i = 20; i+1; --i) {
		if (dep[parent[x][i]] >= dep[y]) {
			x = parent[x][i];
		}
	}
	
	if (x == y) return x;
	
	for (int i = 20; i+1; --i) {
		if (parent[x][i] != parent[y][i]) {
			x = parent[x][i];
			y = parent[y][i];
		}
	}
	return parent[x][0];
}

int get_max(int u, int lca, int limit) {
	int res = 0;
	for (int i = 20; i+1; --i) {
		if (dep[parent[u][i]] >= dep[lca]) {
			if (maxx[u][i] < limit) {
				res = max(res, maxx[u][i]);
			}
			if (maxx2[u][i] < limit) {
				res = max(res, maxx2[u][i]);
			}
			u = parent[u][i];
		}
	}
	return res;
}

void init() {
	memset(head, -1, sizeof head);
	tot = 0;
}

void solve(){
	init();
	cin >> N >> M;
	
	int u, v, w;
	for (int i = 1; i <= M; ++i) {
		cin >> u >> v >> w;
		node[i] = {u, v, w};
	}
	
	sort(node+1, node+1+M, [](Node a, Node b){return a.w < b.w;});
	
	for (int i = 1; i <= N; ++i) {
		father[i] = i;
	}
	
	int done = 1;
	int x, y;
	int ans = 0;
	for (int i = 1; i <= M && done < N; ++i) {
		x = find(node[i].x);
		y = find(node[i].y);
		if (x == y) continue;
		use[i] = 1;
		ans += node[i].w;
		++done;
		father[x] = y;
		addEdge(node[i].x, node[i].y, node[i].w);
	}
	
	dfs(1, 0);
	
	int res = 1e18;
	for (int i = 1; i <= M; ++i) {
		if (use[i]) continue;
		x = node[i].x;
		y = node[i].y;
		
		int lca = LCA(x, y);
		int a = get_max(x, lca, node[i].w);
		int b = get_max(y, lca, node[i].w);
		res = min(res, ans - max(a, b) + node[i].w);
	}
	cout << res;
}

signed main()
{
	#ifndef ONLINE_JUDGE
	//FILE_IN
	FILE_OUT
	#endif
	int T = 1;//cin >> T;
	while (T--) solve();

	return AC;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hexrt

客官,请不要给我小费!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值