CF1927F Microcycle

DE_aemmprty發表於2024-03-22

環的權值為邊權最小值,可以想到從大到小遍歷權值,如果一條邊加入後出現了環說明這條邊的邊權就是整個環的權值。

類似 Kruskal,我們把邊權從大到小排序,然後用並查集維護連通情況,算出最小的權值。然後跑 dfs 找環輸出方案。時間複雜度 \(\mathcal{O}(m\log{m} + n)\)

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 7;

int read() {
    char c = getchar();
    int x = 0, p = 1;
    while ((c < '0' || c > '9') && c != '-') c = getchar();
    if (c == '-') p = -1, c = getchar();
    while (c >= '0' && c <= '9')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x * p;
}

int n, m;
vector <int> to[N];

struct Edge {
	int u, v, w;
	bool operator < (const Edge p) const {
		return w > p.w;
	}
} t[N];

struct DSU {
	int fa[N];
	void init() {
		for (int i = 1; i <= n; i ++) fa[i] = i;
	}
	int find(int x) {
		return x == fa[x] ? x : (fa[x] = find(fa[x]));
	}
	void merge(int i, int j) {
		int x = find(i), y = find(j);
		fa[x] = y;
	}
} D;

bool vis[N];
stack <int> st;
bool flg;

void dfs(int u, int p, int res) {
	vis[u] = 1; st.push(u);
	if (u == p) {
		flg = 1; cout << res << ' ' << (int) st.size() << '\n';
		while (!st.empty()) {
			cout << st.top() << ' ';
			st.pop();
		}
		cout << '\n';
		return ;
	}
	for (int v : to[u]) {
		if (!vis[v]) {
			dfs(v, p, res);
			if (flg) return ;
		}
	}
	st.pop();
}

void solve() {
	n = read(), m = read();
	for (int i = 1; i <= n; i ++)
		to[i].clear();
	for (int i = 1; i <= m; i ++)
		t[i].u = read(), t[i].v = read(), t[i].w = read();
	sort(t + 1, t + m + 1); D.init();
	long long ans = 2e18; flg = 0;
	for (int i = 1; i <= m; i ++) {
		int u = t[i].u, v = t[i].v, w = t[i].w;
		if (D.find(u) != D.find(v)) {
			D.merge(u, v);
		} else {
			ans = i;
		}
	}
	fill(vis + 1, vis + n + 1, 0);
	for (int i = 1; i < ans; i ++) {
		to[t[i].u].push_back(t[i].v);
		to[t[i].v].push_back(t[i].u);
	}
	dfs(t[ans].u, t[ans].v, t[ans].w);
}

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

相關文章