CF1583E Moment of Bloom 題解

rlc202204發表於2024-03-09

題意:

給定一張 \(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; 
}

相關文章