题解:P15961 [ICPC 2018 Jakarta R] Boomerangs

这真是紫题吗,\(5\text{ min}\) 击杀了。

对每个连通块分别做,猜测一个连通块的答案为 \(\lfloor m/2\rfloor\)

建出一棵 DFS 生成树,自底向上做。对于当前点 \(u\),将 \(u\) 未匹配的邻边两两配对,若有奇数条邻边则把 \((u,fa_u)\) 剩下来。这样只会在根节点处有 \(m\bmod{2}\) 条边无法匹配。于是我们就得到了构造。

随便实现就是 \(\mathcal{O}(n+m)\) 的了。

代码
#include <bits/stdc++.h>

using namespace std;

using pii = pair<int, int>;
const int N = 1e5 + 5;

int n, m;
bool visP[N], visE[N];
pii E[N];
vector<pii> T[N];
vector<tuple<int, int, int>> ans;

void dfs(int x, int fx) {
	visP[x] = 1;
	for (auto [y, id] : T[x]) if (!visP[y]) dfs(y, x);
	vector<int> edges;
	int faId = 0;
	for (auto [y, id] : T[x]) {
		if (visE[id]) continue;
		if (y == fx) faId = id;
		else edges.emplace_back(id);
	}
	if (faId) edges.emplace_back(faId);
	for (int i = 0; i + 1 < edges.size(); i += 2) {
		int e1 = edges[i], e2 = edges[i + 1];
		visE[e1] = visE[e2] = 1;
		auto [u1, v1] = E[e1];
		auto [u2, v2] = E[e2];
		int y = u1 == x ? v1 : u1, z = u2 == x ? v2 : u2;
		ans.emplace_back(y, x, z);
	}
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n >> m;
	for (int i = 1, u, v; i <= m; ++i) {
		cin >> u >> v;
		T[u].emplace_back(v, i), T[v].emplace_back(u, i);
		E[i] = {u, v};
	}
	for (int i = 1; i <= n; ++i) if (!visP[i]) dfs(i, 0);
	cout << ans.size() << '\n';
	for (auto [u, v, w] : ans) cout << u << ' ' << v << ' ' << w << '\n';
	return 0;
}
posted @ 2026-03-27 19:13  P2441M  阅读(4)  评论(0)    收藏  举报