HYSBZ - 1977 次小生成树 Tree

题意:

给定一个有 n 个点、m 条边的无向带权图,求严格次小生成树。(n <= 1e5, m <= 3e5)

链接:

https://vjudge.net/problem/HYSBZ-1977

解题思路:

求非严格次小生成树时,替换路径上的最大边,加入的边权可能与其相等,故倍增时多维护一个路径上严格的次大值即可。

参考代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 3e5 + 5;
const int maxm = 6e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

vector<pii> G[maxn];
struct Edge{
	int u, v, w;
	bool operator < (const Edge &o) const{
		return w < o.w;
	}
} ei[maxn];
int pre[maxn], dep[maxn], fa[maxn][21];
int mx[maxn][21], mx2[maxn][21];
int n, m, p;

int fin(int x){

	return x == pre[x] ? x : pre[x] = fin(pre[x]);
}

ll kruskal(){

	sort(ei + 1, ei + 1 + m);
	for(int i = 1; i <= n; ++i) G[i].clear(), pre[i] = i;
	int cnt = 1; ll ret = 0; p = 0;
	for(int i = 1; i <= m; ++i){

		int u = ei[i].u, v = ei[i].v, w = ei[i].w;
		int x = fin(u), y = fin(v);
		if(cnt < n && x != y){

			pre[x] = y, ++cnt, ret += w;
			G[u].pb({w, v}), G[v].pb({w, u});
		}
		else ei[++p] = ei[i];
	}
	return ret;
}

void dfs(int u, int f){

	dep[u] = dep[f] + 1;
	for(int i = 0; i < sz(G[u]); ++i){

		int v = G[u][i].second, w = G[u][i].first;
		if(v == f) continue;
		fa[v][0] = u, mx[v][0] = w, mx2[v][0] = -1;
        for(int i = 1; i <= 20; ++i){

	    	fa[v][i] = fa[fa[v][i - 1]][i - 1];
	    	mx[v][i] = max(mx[v][i - 1], mx[fa[v][i - 1]][i - 1]);
	    	if(mx[v][i - 1] == mx[fa[v][i - 1]][i - 1]) mx2[v][i] = max(mx2[v][i - 1], mx2[fa[v][i - 1]][i - 1]);
	    	else if(mx[v][i - 1] > mx[fa[v][i - 1]][i - 1]) mx2[v][i] = max(mx2[v][i - 1], mx[fa[v][i - 1]][i - 1]);
	    	else mx2[v][i] = max(mx[v][i - 1], mx2[fa[v][i - 1]][i - 1]);
	    }
		dfs(v, u);
	}
}

void change(int &ret1, int &ret2, int u, int i){

	if(mx[u][i] > ret1) ret2 = max(ret1, mx2[u][i]), ret1 = mx[u][i];
	else if(mx[u][i] == ret1) ret2 = max(ret2, mx2[u][i]);
	else ret2 = max(ret2, mx[u][i]);
}

pii getMax(int u, int v){

	if(dep[u] < dep[v]) swap(u, v);
	int ret1 = -1, ret2 = -1;
	for(int i = 20; i >= 0; --i){

		if(dep[fa[u][i]] >= dep[v]){

			change(ret1, ret2, u, i);
			u = fa[u][i];
		}
	}
	if(u == v) return {ret1, ret2};
	for(int i = 20; i >= 0; --i){

		if(fa[u][i] != fa[v][i]){

			change(ret1, ret2, u, i);
			change(ret1, ret2, v, i);
			u = fa[u][i], v = fa[v][i];
		}
	}
	change(ret1, ret2, u, 0);
	change(ret1, ret2, v, 0);
	return {ret1, ret2};
}

int main(){

//	ios::sync_with_stdio(0); cin.tie(0);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; ++i){

		scanf("%d%d%d", &ei[i].u, &ei[i].v, &ei[i].w);
	}
	ll ret = kruskal(), ret2 = 1ll << 62;
	mem(mx[1], -1), mem(mx2[1], -1); dfs(1, 0);
	for(int i = 1; i <= p; ++i){

		int u = ei[i].u, v = ei[i].v, w = ei[i].w;
		pii tmp = getMax(u, v);
		if(tmp.first == w && tmp.second == -1) continue;
		if(tmp.first != w) ret2 = min(ret2, ret + w - tmp.first);
		else ret2 = min(ret2, ret + w - tmp.second);
	}
	printf("%lld\n", ret2);
	return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1271

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/101358364
今日推荐