CF1499G Graph Coloring【构造,并查集】

身为一名新时代的好学生,你每天都要按时完成作业。

给定左右分别 \(n_1,n_2\) 个点 \(m\) 条边的无重边的二分图,之后 \(q\) 天,每天的作业可能是:

  • \(\texttt{1 u v}\):表示在左边第 \(u\) 个点与右边第 \(v\) 个点连一条边,再求出给边染红蓝色的一种方案,使得 \(\sum_{v\in V}|r(v)-b(v)|\) 尽量小,其中 \(V\) 是点集,\(r(v),b(v)\) 表示与 \(v\) 相连的红/蓝边数量。由于检查作业太麻烦了,你只需要向老师提交 \((\sum_{i\in R}2^i)\bmod 998244353\) 的值。由于方案不唯一,老师不会检查你提交的值是否合法。
  • \(\texttt 2\):突击检查作业,你需要提交昨天的完整作业。为了确保你每天都按时完成作业,你提交的方案必须满足你昨天提交的值。

\(n_1,n_2,m,q\le 2\cdot 10^5\),交互式强制在线,保证 \(2\) 操作不超过 \(10\) 个且每个 \(2\) 操作的上一个都是 \(1\) 操作。


如果不带修的话,这事一个我不会的经典问题。

显然一个答案的下界是 \(\sum_{v\in V}\deg(v)\bmod 2\),构造证明也可以取到这个下界。

使用并查集维护边集,维护一堆环/链集合,其中链端点都是度数为奇数的点,然后相间染色即为合法方案。具体实现上处理深度奇偶性即可。

时间复杂度 \(O(n_1+n_2+(m+q)\alpha(m+q))\)

#include<bits/stdc++.h>
#define PB emplace_back
#define fi first
#define se second
#define MP make_pair
using namespace std;
typedef pair<int, bool> pib;
const int N = 400003, mod = 998244353;
template<typename T>
void read(T &x){
    int ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
} void qmo(int &x){x += x >> 31 & mod;}
int n1, n2, m, q, pw[N], mat[N], siz[N], fa[N], red[N], sum[N], res;
bool val[N];
pib getf(int x){
    if(fa[x] == x) return MP(x, false);
    auto [f, r] = getf(fa[x]);
    return MP(fa[x] = f, val[x] ^= r);
}
void comb(int u, int v){
    auto [f1, x] = getf(u);
    auto [f2, y] = getf(v);
    if(f1 == f2) return;
    if(siz[f1] > siz[f2]){swap(f1, f2); swap(x, y);}
    siz[f2] += siz[f1]; fa[f1] = f2;
    qmo(sum[f2] += sum[f1] - mod);
    qmo(red[f2] += red[f1] - mod);
    if(val[f1] = (x == y)){
        int _ = sum[f1] - (red[f1]<<1);
        if(_ >= 0) _ -= mod; if(_ < -mod) _ += mod;
        qmo(res += _); qmo(red[f2] += _);
    }
}
void add(int u, int v, int k){
    sum[k] = pw[k+1]; siz[k] = 1; fa[k] = k;
    if(~mat[u]){comb(mat[u], k); mat[u] = -1;} else mat[u] = k;
    if(~mat[v]){comb(mat[v], k); mat[v] = -1;} else mat[v] = k;
}
int main(){
    read(n1); read(n2); read(m); pw[0] = 1;
    for(int i = 1;i < (N<<1);++ i) qmo(pw[i] = (pw[i-1]<<1) - mod);
    memset(mat, -1, sizeof mat);
    for(int i = 0, u, v;i < m;++ i){
        read(u); read(v); add(u-1, v+n1-1, i);
    } read(q);
    while(q --){
        int op; read(op);
        if(op == 1){
            int u, v; read(u); read(v);
            add(u-1, v+n1-1, m++);
            printf("%d\n", res); fflush(stdout);
        } else {
            vector<int> ans;
            for(int i = 0;i < m;++ i)
                if(getf(i).se) ans.PB(i+1);
            printf("%ld", ans.size());
            for(int u : ans) printf(" %d", u);
            putchar('\n'); fflush(stdout);
        }
    }
}
posted @ 2021-04-21 16:48  mizu164  阅读(155)  评论(0编辑  收藏  举报