[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;
}
posted @ 2023-11-26 10:29  TernaKagiri  阅读(8)  评论(0编辑  收藏  举报  来源