zoukankan      html  css  js  c++  java
  • 【洛谷 P3402】 【模板】可持久化并查集

    题目链接

    可持久化并查集,就是用可持久化线段树维护每个版本每个节点的父亲,这样显然是不能路径压缩的,否则我们需要恢复太多状态。
    但是这并不影响我们启发式合并,于是,每次把深度小的连通块向深度大的上并就好了。

    #include <cstdio>
    #define re register
    inline int read(){
        int s = 0, w = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();}
        while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0',ch = getchar();
        return s * w;
    }
    const int MAXN = 100010;
    const int MAXM = 200010;
    struct SegTree{
        int lc, rc, val, dep;
    }t[MAXN * 20];
    int cnt, opt, a, b, root[MAXM], rt, n, m;
    int build(int l, int r){
        int id = ++cnt;
        if(l == r){
          t[id].val = l;
          return id;
        }
        int mid = (l + r) >> 1;
        t[id].lc = build(l, mid);
        t[id].rc = build(mid + 1, r);
        return id;
    }
    int query(int now, int l, int r, int x){
        if(l == r) return now;
        int mid = (l + r) >> 1;
        return x <= mid ? query(t[now].lc, l, mid, x) : query(t[now].rc, mid + 1, r, x);
    }
    int update(int now, int l, int r, int x, int p){
        int id = ++cnt;
        t[id] = t[now];
        if(l == r){ t[id].val = p; return id; }
        int mid = (l + r) >> 1;
        if(x <= mid) t[id].lc = update(t[now].lc, l, mid, x, p);
        else t[id].rc = update(t[now].rc, mid + 1, r, x, p);
        return id;
    }
    int find(int x){
        int now = query(rt, 1, n, x);
        if(t[now].val == x) return now;
        return find(t[now].val);
    }
    void updep(int now, int l, int r, int x){
        if(l == r){ ++t[now].dep; return; }
        int mid = (l + r) >> 1;
        if(x <= mid) updep(t[now].lc, l, mid, x);
        else updep(t[now].rc, mid + 1, r, x);
    }
    int main(){
        n = read(); m = read();
        root[0] = build(1, n);
        for(int i = 1; i <= m; ++i){
          opt = read();
          rt = root[i - 1];
          if(opt == 1){
            a = read(); b = read();
            int fa = find(a), fb = find(b);
            if(t[fa].dep < t[fb].dep){
              root[i] = update(root[i - 1], 1, n, t[fa].val, t[fb].val);
              if(t[fa].dep == t[fb].dep) updep(root[i], 1, n, t[fb].val);
            }
            else{
              root[i] = update(root[i - 1], 1, n, t[fb].val, t[fa].val);
              if(t[fa].dep == t[fb].dep) updep(root[i], 1, n, t[fa].val);
            }
          }
          if(opt == 2){
            rt = root[i] = root[read()];
          }
          if(opt == 3){
            rt = root[i] = root[i - 1];
            printf("%d
    ", t[find(read())].val == t[find(read())].val);
          }
        }
        return 0;
    }
    
    
  • 相关阅读:
    代理类和装饰类的区别
    spring mvc 处理映射的几种方式
    如何深入浅出的理解跳转方式:重定向和请求转发
    springMVC拦截配置
    ※版本管理※=>☆SVN工具=>※解决地域麻烦※№→搭建自己的网络SVN (SourceForge 免费) [转]
    权力社会? 金钱社会? 透过现象看本质-让权力和金钱的力量沿着制度的河道流淌,才是社会稳定的基石
    自己封装的CMusic类 【转】
    VC++中MCI播放音频文件 【转】
    DevExpress.XtraGrid 【转】
    C# Process.Start()方法详解 [转]
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/9935355.html
Copyright © 2011-2022 走看看