[ABC244G] Construct Good Path
图比较难做,考虑跑出一棵生成树,只用上面的边。
显然先把每条边全用上,然后注意到每次可以将一条边经过的次数 $+2$,dfs 一遍就跑完了。这里 dfs 是子树经过次数满足题目条件下,从 $u$ 回到 $u$ 的方案构造;如果 dfs 完儿子 $u$ 不满足条件,就让 $fa\to u$ 这条边经过次数 $+2$,即,让原来的 $u$ 变为 $u\to fa\to u$。
最后 $1$ 可能不满足限制,因为 $1$ 没有父亲;但是实际上因为最后肯定会回到 $1$,所以把最后回到的那个 $1$ 去掉就行了。
首先一次正常跑的总个数是 $2n$,每次调整只会加 $2$ 个点,所以长度不超过 $4n$。
具体可以看代码实现。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e5 + 10;
int n, m;
vector<int> g[maxn];
int fa[maxn];
int c[maxn];
int a[maxn];
char ch;
vector<int> ans;
int find(int x) {
return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void dfs(int u, int fa) {
ans.push_back(u);
for (int v : g[u]) {
if (v == fa) continue;
dfs(v, u);
ans.push_back(u);
}
if (u != 1 && (c[u] & 1) != a[u]) {
c[fa]++, c[u]++;
ans.push_back(fa);
ans.push_back(u);
}
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) fa[i] = i;
c[1] = 1;
for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v;
if (find(u) != find(v)) {
fa[find(u)] = find(v);
g[u].push_back(v);
g[v].push_back(u);
c[u]++, c[v]++;
}
}
for (int i = 1; i <= n; i++) cin >> ch, a[i] = ch - '0';
dfs(1, 0);
bool fl = (c[1] & 1) != a[1];
cout << ans.size() - fl << endl;
for (int i = 0; i + fl < ans.size(); i++) cout << ans[i] << " ";
return 0;
}