ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

可撤销并查集

2021-10-31 13:33:04  阅读:146  来源: 互联网

标签:int 查集 撤销 fa dx dy ufs size


之前没有写过可撤销并查集,这里整理一下.  

普通并查集是不支持撤销/断边操作的.  

但是如果加边顺序是 $(1,2,3,4,5)$, 断边顺序是 $(5,4,3,2,1)$ 的话是可以维护的.  

我们只需要用一个启发式合并的并查集加上栈来存储合并信息即可.  

这样做可行,是因为始终是向上合并,并且删除时是从上向下删除的.   

具体代码如下: 

namespace ufs {
    stack<int>S; 
    int dis[N], fa[N], size[N];  
    void init() {
        for(int i=1;i<N;++i) {
            dis[i] = 0, fa[i] = i, size[i] = 1; 
        }
    }
    int find(int x) {
        return fa[x] == x ? fa[x] : find(fa[x]); 
    }
    int dist(int x) {
        return fa[x] == x ? dis[x] : dis[x] ^ dist(fa[x]); 
    }
    void merge(int x, int y) {
        int dx = dist(x); 
        int dy = dist(y); 
        x = find(x), y = find(y);  
        if(size[x] > size[y]) {
            swap(x, y); 
            swap(dx, dy);  
        }
        // size[y] > size[x] 
        // 令 f[x] -> y 
        S.push(x); 
        size[y] += size[x];  
        fa[x] = y, dis[x] = dx ^ dy ^ 1;  
    }
    void undo(int si) {
        // 撤销.  
        while(S.size() > si) {
            int p = S.top(); S.pop();  
            size[fa[p]] -= size[p];  
            fa[p] = p, dis[p] = 0;     
        }   
    }
}; 

  

在撤销的时候删除 $\mathrm{x}$ 对 $\mathrm{fa[x]}$ 的影响就好了,这一般是较好维护的.  

1.二分图 /【模板】线段树分治

来源:luogu5787 

在这道题中,如果说没有删边操作则可以直接利用加权并查集维护奇偶性.  

然后有删边时间的话就利用线段树分治存边,利用加权并查集在线段树上合并和撤销即可.  

#include <cstdio>
#include <vector>  
#include <cstring>
#include <stack>
#include <algorithm>
#define N  200009 
#define ll long long 
#define pb push_back 
#define ls now << 1 
#define rs now << 1 | 1
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;
namespace ufs {
    stack<int>S; 
    int dis[N], fa[N], size[N];  
    void init() {
        for(int i=1;i<N;++i) {
            dis[i] = 0, fa[i] = i, size[i] = 1; 
        }
    }
    int find(int x) {
        return fa[x] == x ? fa[x] : find(fa[x]); 
    }
    int dist(int x) {
        return fa[x] == x ? dis[x] : dis[x] ^ dist(fa[x]); 
    }
    void merge(int x, int y) {
        int dx = dist(x); 
        int dy = dist(y); 
        x = find(x), y = find(y);  
        if(size[x] > size[y]) {
            swap(x, y); 
            swap(dx, dy);  
        }
        // size[y] > size[x] 
        // 令 f[x] -> y 
        S.push(x); 
        size[y] += size[x];  
        fa[x] = y, dis[x] = dx ^ dy ^ 1;  
    }
    void undo(int si) {
        // 撤销.  
        while(S.size() > si) {
            int p = S.top(); S.pop();  
            size[fa[p]] -= size[p];  
            fa[p] = p, dis[p] = 0;     
        }   
    }
}; 
int n, m, K;   
struct oper {
    int x, y;  
    oper(int x=0,int y=0):x(x),y(y){}  
}; 
vector<oper>G[N << 2];  
void update(int l, int r, int now, int L, int R, oper v) {
    if(l >= L && r <= R) {
        G[now].pb(v); 
        return ; 
    }
    int mid = (l + r) >> 1; 
    if(L <= mid) update(l, mid, ls, L, R, v); 
    if(R  > mid) update(mid + 1, r, rs, L, R, v);  
}
void dfs(int l, int r, int now, int flag) {
    int cur = ufs::S.size(); 
    if(!flag) {
        // 若还没构成二分图,则可以加边.
        for(int i = 0 ; i < G[now].size() ; ++ i) {
            int x = G[now][i].x; 
            int y = G[now][i].y;  
            int px = ufs::find(x); 
            int py = ufs::find(y); 
            if(px != py) {
                ufs::merge(x, y); 
            }
            else {
                int dx = ufs::dist(x); 
                int dy = ufs::dist(y); 
                if(dx ^ dy) {
                    continue;
                }
                else {
                    flag = 1; 
                    break; 
                }
            }
        }
    }
    if(l == r) {
        printf("%s\n", flag ? "No" : "Yes");  
        return ; 
    }
    int mid = (l + r) >> 1; 
    dfs(l, mid, ls, flag); 
    dfs(mid + 1, r, rs, flag);  
    ufs::undo(cur); 
}
int main() {
    // setIO("input"); 
    scanf("%d%d%d",&n,&m,&K);  
    ufs::init(); 
    for(int i = 1; i <= m ; ++ i) {
        int x, y, l, r; 
        scanf("%d%d%d%d",&x, &y, &l, &r);    
        update(0, K - 1, 1, l, r - 1, oper(x, y));  
    }
    // 处理完了, 可以遍历了.  
    dfs(0, K - 1, 1, 0); 
    return 0; 
}

  

标签:int,查集,撤销,fa,dx,dy,ufs,size
来源: https://www.cnblogs.com/brady12/p/15489195.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有