CF1583E Moment of Bloom 题解

题意:

给定一张 \(n\) 个点 \(m\) 条边无向连通图,以及 \(q\) 个点对 \((a,b)\),出事每条边权值为 \(0\)。对于每个点对我们需要找一条从一个点到另一个点的简单路径,将所有边的权值加一。要求构造一种方案使得每条边权值都是偶数。如果不行,输出最少还要几个点对才能满足要求。

\(n,m \le 10^5\)

思路:

这个条件不难联想到欧拉回路,我们尝试构造一个图 \(G'\) 使得这 \(q\) 个点对是这张图的所有边。

如果这张图存在欧拉回路,则我们只用在回路最后一条边反向走一遍便能满足要求。回到原图,随便一棵生成树上走两点路径即可。

如果不存在欧拉回路,说明一定有奇点,这就会导致有的边边权是奇数。具体而言,我们记录每个点所有相邻边的边权和的奇偶性。显然一个点对只会改变两个端点,所以如果不存在欧拉回路,则必然不成立。需要再加上奇点个数除以二个。

然后就没了。

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3e5 + 5;

int n, m, q;
vector<int> e[N], E[N];
int cnt[N] = {0};
int a[N] = {0}, b[N] = {0};

int p[N] = {0};
int fnd(int x) {
	if (p[x] == x)
		return x;
	return p[x] = fnd(p[x]);
}
void unn(int x, int y) {
	p[fnd(x)] = fnd(y);
}

int pr[N] = {0}, dth[N] = {0};

void srh(int x, int Pr, int d) {
	dth[x] = d, pr[x] = Pr;
	for (auto i: E[x])
		if (i != Pr)
			srh(i, x, d + 1);
}

int fnd_lca(int x, int y) {
	if (x == y)
		return x;
	if (dth[x] < dth[y])
		swap(x, y);
	return fnd_lca(pr[x], y);
}

void fnd_prx(int x, int anc) {
	if (x == anc)
		return;
	printf("%d ", x);
	fnd_prx(pr[x], anc);
}

void fnd_suf(int x, int anc) {
	if (x == anc)
		return;
	fnd_suf(pr[x], anc);
	printf("%d ", x);
}

void fnd_pth(int x, int y) {
	int lca = fnd_lca(x, y);
	printf("%d\n", dth[x] + dth[y] - 2 * dth[lca] + 1);
	fnd_prx(x, lca);
	printf("%d ", lca);
	fnd_suf(y, lca);
	printf("\n");
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1, u, v; i <= m; i++) {
		scanf("%d%d", &u, &v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		scanf("%d%d", &a[i], &b[i]);
		cnt[a[i]]++, cnt[b[i]]++;
	}
	int odd = 0;
	for (int i = 1; i <= n; i++)
		odd += cnt[i] % 2;
	if (odd > 0) {
		printf("No\n%d\n", odd / 2);
		return 0;
	}
	
	for (int i = 1; i <= n; i++)
		p[i] = i;
	for (int i = 1; i <= n; i++)
		for (auto j: e[i])
			if (fnd(i) != fnd(j)) {
				unn(i, j);
				E[i].push_back(j);
				E[j].push_back(i);
			}
	srh(1, 1, 1);
	printf("YES\n");
	for (int i = 1; i <= q; i++) 
		fnd_pth(a[i], b[i]);
	return 0; 
}
posted @ 2024-03-09 19:30  rlc202204  阅读(49)  评论(0)    收藏  举报