zoukankan      html  css  js  c++  java
  • #扩展域并查集,线段树分治#CF576E Painting Edges

    题目链接

    题目翻译

    • 给定一张 (n) 个点 (m) 条边的无向图。
    • 一共有 (k) 种颜色,一开始,每条边都没有颜色。
    • 定义合法状态为仅保留染成 (k) 种颜色中的任何一种颜色的边,图都是一张二分图。
    • (q) 次操作,第 (i) 次操作将第 (e_i) 条边的颜色染成 (c_i)
    • 但并不是每次操作都会被执行,只有当执行后仍然合法,才会执行本次操作。
    • 你需要判断每次操作是否会被执行。
    • 数据范围:(n,m,q le 5 imes 10^5)(k le 50)
      翻译出处

    解题过程

    首先二分图即保证图中不存在奇环,这可以用带权并查集或扩展域并查集实现,需要带一个(log)

    这题比较巧妙的是执行后仍然合法才会执行本次操作,看起来像强制在线,

    其实不然,如果不合法直接将后面的边所染的颜色修改即可

    由于修改染色比较困难,考虑线段树分治,那么仅仅需要可撤销并查集即可,由于有(k)种颜色,要开(k)个并查集

    代码

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #define rr register
    using namespace std;
    const int N = 1000011;
    vector<int>K[N << 1];
    int stad[N], tad[N], stac[N], tac[N], tot, tod;
    int X[N], Y[N], U[N], V[N], cad[N], cac[N], last[N], Q, n, m, k;
    inline void update(int rt, int l, int r, int x, int y, int z) {//在子区间内插入操作
        if (l == x && r == y) {
            K[rt].push_back(z);
            return;
        }
    
        rr int mid = (l + r) >> 1;
    
        if (y <= mid)
            update(rt << 1, l, mid, x, y, z);
        else if (x > mid)
            update(rt << 1 | 1, mid + 1, r, x, y, z);
        else
            update(rt << 1, l, mid, x, mid, z), update(rt << 1 | 1, mid + 1, r, mid + 1, y, z);
    }
    struct Union_Set {
        int f[N], dep[N];
        inline signed getf(int u) {//求子树的祖先
            return f[u] == u ? u : getf(f[u]);
        }
        inline void Merge(int col, int x, int y) {//合并两棵子树
            rr int fa = getf(x), fb = getf(y);
    
            if (fa == fb)
                return;
    
            if (dep[fa] > dep[fb])
                fa ^= fb, fb ^= fa, fa ^= fb;
    
            if (dep[fa] == dep[fb]) {
                stad[++tod] = fb, tad[tod] = dep[fb];
                ++dep[fb], cad[tod] = col;
            }
    
            stac[++tot] = fa, tac[tot] = f[fa], f[fa] = fb, cac[tot] = col;
        }
    } T[51];
    inline void dfs(int rt, int l, int r) {
        rr int len = K[rt].size(), Tot = tot, Tod = tod;
    
        for (rr int i = 0; i < len; ++i) {
            rr int t = K[rt][i];
            T[V[t]].Merge(V[t], X[U[t]] + n, Y[U[t]]),
            T[V[t]].Merge(V[t], X[U[t]], Y[U[t]] + n);
        }
    
        rr int mid = (l + r) >> 1;
    
        if (l == r) {
            rr int fa = T[V[l]].getf(X[U[l]]), fb = T[V[l]].getf(Y[U[l]]);
    
            if (fa == fb)
                puts("NO"), V[l] = last[U[l]];//这条边直接改
            else
                puts("YES"), last[U[l]] = V[l];//更新边的颜色
        } else
            dfs(rt << 1, l, mid), dfs(rt << 1 | 1, mid + 1, r);
    
        for (; tot > Tot; --tot)//撤销操作
            T[cac[tot]].f[stac[tot]] = tac[tot];
    
        for (; tod > Tod; --tod)
            T[cad[tod]].dep[stad[tod]] = tad[tod];
    }
    signed main() {
        scanf("%d%d%d%d",&n,&m,&k,&Q);
        for (rr int j = 1; j <= k; ++j)
            for (rr int i = 1; i <= n * 2; ++i)
                T[j].f[i] = i, T[j].dep[i] = 1;
    
        for (rr int i = 1; i <= m; ++i)
            scanf("%d%d",&X[i],&Y[i]), last[i] = Q + 1;
    
        for (rr int i = 1; i <= Q; ++i)
            U[i] = iut(), V[i] = iut();
    
        for (rr int i = Q; i; --i) {
            if (i < last[U[i]] - 1)
                update(1, 1, Q, i + 1, last[U[i]] - 1, i);//注意i的位置只判定不修改
    
            last[U[i]] = i;
        }
    
        for (rr int i = 1; i <= m; ++i)
            last[i] = 0;
    
        dfs(1, 1, Q);
        return 0;
    }
    
  • 相关阅读:
    【索引】SyntaxHighlighter 使用参考
    【索引】博客心得
    SyntaxHighlighter 使用参考(一) 概述
    PEGA 十合一吉他控制器连接电脑玩《吉他英雄3》
    从SourceForge上获取CVS管理的开源代码
    从SourceForge上获取SVN管理的开源代码
    整数哈希介绍
    回文时间
    D2js 是如何处理并发的
    Windows 安装JRuby 生成 war 到 tomcat 运行
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14738147.html
Copyright © 2011-2022 走看看