其他分享
首页 > 其他分享> > Codeforces 19E DFS 树

Codeforces 19E DFS 树

作者:互联网

题意

传送门 Codeforces 19E Fairy

题解

若图中不存在非二分图的连通分量,则任意一边删除后仍是二分图;若图中存在大于一个非二分图的连通分量,则不可能通过删除一条边使之变为二分图。故讨论仅存在一个非二分图的连通分量的情况即可。

考虑 D F S DFS DFS 树,将树上节点进行二分图染色。对于非树边,若其端点颜色相同,则出现奇环,称之为非法的非树边;反之为合法的非树边。

若删除的边 e e e 为非树边,当且仅当它是图中唯一的非法的非树边。充分性显然;必要性,使用反证法,若存在多条非法的非树边,删除 e e e 后不会影响其他非法的非树边与树边构成的奇环,此时不构成二分图,证毕。

若删除的边 e e e 是树边,当且仅当树边被所有非法非树边覆盖,且不被任何合法非树边覆盖(覆盖,即被非树边两端点所在的树上路径所包含)。删除 e e e 后, D F S DFS DFS 树划分为子树与其余部分。图存在合法染色方案,当且仅当将子树染色黑白交换能够得到合法方案,分别讨论非法/合法非树边即可得证。

D F S DFS DFS 树的非树边一定连接某个节点与其祖先节点,那么可以在构造 D F S DFS DFS 树的过程中进行类似树上点差分并求前缀和的操作,统计树边被非法/合法非树边覆盖的次数。

总时间复杂度 O ( m ) O(m) O(m)。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
#define pb push_back
const int MAXN = 1E4 + 5;
int N, M, dep[MAXN], conf, rec_id;
int sum[2][MAXN];
bool chs[MAXN], used[MAXN];
struct edge
{
    int to, id;
};
vector<edge> G[MAXN];

void dfs(int u, int p, int d)
{
    dep[u] = d;
    for (auto &e : G[u])
    {
        int v = e.to;
        if (dep[v] == -1)
        {
            dfs(v, u, d + 1);
            rep(i, 0, 2) sum[i][u] += sum[i][v];
        }
        else if (v != p)
        {
            if (dep[u] < dep[v])
                continue;
            int d = (dep[u] - dep[v]) & 1;
            ++sum[d ^ 1][u], --sum[d ^ 1][v];
            if (d ^ 1)
                ++conf, rec_id = e.id;
        }
    }
}

void judge(int u)
{
    used[u] = 1;
    for (auto &e : G[u])
    {
        int v = e.to;
        if (!used[v])
        {
            judge(v);
            if (sum[0][v] == 0 && sum[1][v] == conf)
                chs[e.id] = 1;
        }
    }
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N >> M;
    rep(i, 0, M)
    {
        int u, v;
        cin >> u >> v;
        --u, --v;
        G[u].pb({v, i}), G[v].pb({u, i});
    }
    memset(dep, -1, sizeof(dep));
    rep(u, 0, N) if (dep[u] == -1) dfs(u, -1, 0);
    rep(u, 0, N) if (!used[u]) judge(u);
    if (conf == 1)
        chs[rec_id] = 1;
    if (conf == 0)
    {
        cout << M << '\n';
        rep(i, 0, M) cout << i + 1 << (i + 1 == M ? '\n' : ' ');
    }
    else
    {
        int t = 0;
        rep(i, 0, M) if (chs[i])++ t;
        cout << t << '\n';
        rep(i, 0, M) if (chs[i]) cout << i + 1 << (!--t ? '\n' : ' ');
    }
    return 0;
}

标签:int,sum,Codeforces,DFS,dep,19E,非树边,id
来源: https://blog.csdn.net/neweryyy/article/details/122658520