• CF1499G Graph Coloring【构造,并查集】


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

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

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

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


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

    显然一个答案的下界是 (sum_{vin V}deg(v)mod 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
    ", 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('
    '); fflush(stdout);
            }
        }
    }
    
  • 相关阅读:
    一个浏览器循环刷新网页的例子
    Ajax和JSON基础
    HTML-第三章构建模块小结
    HTML-元素属性
    入前端坑的第一天
    JZOJ 【2021.11.10NOIP提高组联考】
    LG P2633 Count on a tree
    JZOJ 7339.改试卷
    [CEOI2017] Building Bridges
    拉格朗日插值法
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/14685867.html
Copyright © 2020-2023  润新知