• [题解] bzoj 3674 可持久化并查集加强版


    - 传送门 -

     http://www.lydsy.com/JudgeOnline/problem.php?id=3674
     

    3674: 可持久化并查集加强版

    Time Limit: 15 Sec  Memory Limit: 256 MB
    Submit: 4218  Solved: 1557

    Description

    自从zkysb出了可持久化并查集后……
    hzwer:乱写能AC,暴力踩标程
    KuribohG:我不路径压缩就过了!
    ndsf:暴力就可以轻松虐!
    zky:……

    n个集合 m个操作
    操作:
    1 a b 合并a,b所在集合
    2 k 回到第k次操作之后的状态(查询算作操作)
    3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
    请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
    0<n,m<=2*10^5

    Sample Input

    5 6
    1 1 2
    3 1 2
    2 1
    3 0 3
    2 1
    3 1 2

    Sample Output

    1
    0
    1  

    - 思路 -

    未加强的在3673,但是啥优化都不加也能过.
    然后做到这题我才发现并查集有种叫按秩合并的优化...我是傻子吗...
    看了第一篇讲解说就是把rank小的接在大的下面
    但是rank是什么....
    于是我就把编号小的接在大的下面...然后就过了...
    可是这和我看到的AC代码好像不一样...
    然后又看了一篇讲解,发现按秩合并是指把数量小的树接到大的上去,通常是用高度来取代这个数量
    ...
    哦我终于看懂了标程了...
    再打一遍,然后发现慢了一倍...
    哦仔细想想按编号来优化也是可以的,除非是8,7,6,5,4,3,2,1这样倒着合并会合出一条链,但是大部分情况下还是可行的,而且也不需要维护什么东西(大概就是这里节省了时间).
    路径压缩...不存在的...怎么可能说我懒得打

     细节见代码.
     

    - 代码 -

    按编号优化:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <ctime>
    #include <cstdlib>
    #define pii pair<int, int>
    #define mp make_pair
    #define ft first
    #define sd second
    #define ls C[rt][0]
    #define rs C[rt][1]
    using namespace std;
    
    template <typename ty> void read(ty &x) {
      x = 0; int f = 1; char ch = getchar();
      while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
      while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
      x *= f;
    }
    template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; }
    template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; }
    template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; }
    template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; }
    
    typedef long long LL;
    typedef double db;
    
    const int inf = 0x7fffffff;
    const int N = 2e5 + 16;
    
    int F[N], V[N*20], C[N*20][2], RT[N], P[N];
    int n, m, sz, lastans;
    
    void build(int &rt, int l, int r) {
      rt = ++sz;
      if (l == r) { V[rt] = l; return; }
      int mid = l + r >> 1;
      build(C[rt][0], l, mid);
      build(C[rt][1], mid + 1, r);
    }
    
    int find(int rt) { return F[rt] == rt ? rt : F[rt] = find(F[rt]); }
    
    int query(int rt, int l, int r, int pos) {
      if (l == r) return V[rt];
      int mid = l + r >> 1;
      if (pos <= mid) return query(C[rt][0], l, mid, pos);
      else return query(C[rt][1], mid + 1, r, pos);
    }
    
    void change(int &now, int pre, int l, int r, int pos, int v) {
      now = ++sz;
      C[now][0] = C[pre][0]; C[now][1] = C[pre][1];
      if (l == r) { V[now] = v; return; }
      int mid = l + r >> 1;
      if (pos <= mid) change(C[now][0], C[pre][0], l, mid, pos, v);
      else change(C[now][1], C[pre][1], mid + 1, r, pos, v);
    }
    
    int get(int rt, int a) {
      int tmp = a;
      while (true) {
        tmp = query(RT[rt], 1, n, tmp);
        if (query(RT[rt], 1, n, tmp) != tmp)
          a = tmp;
        else return tmp;
      }
    }
    
    int main () {
    
      read(n); read(m);
      build(RT[0], 1, n);
    
      for (int i = 1; i <= m; ++ i) {
        F[i] = i;
        int opt, a, b, k;
        read(opt);
        if (opt == 1) {
          read(a); read(b);
          a ^= lastans, b ^= lastans;
          int pre = find(i - 1);
          int tmp1, tmp2;
          tmp1 = get(pre, a);
          tmp2 = get(pre, b);
          if (tmp1 == tmp2) { F[i] = i - 1; continue; }
          if (tmp1 < tmp2) swap(tmp1, tmp2);
          change(RT[i], RT[pre], 1, n, tmp1, tmp2);
        }
        if (opt == 2) {
          read(k);
          k ^= lastans;
          F[i] = find(k);
        }
        if (opt == 3) {
          F[i] = find(i - 1);
          read(a); read(b);
          a ^= lastans, b ^= lastans;
          int tmp, tmp1, tmp2;
          tmp1 = get(F[i], a);
          tmp2 = get(F[i], b);
          if (tmp1 == tmp2) lastans = 1, printf("1
    ");
          else lastans = 0, printf("0
    ");
        }
      }
    
    
      return 0;
    
    }
    

    按秩合并:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <ctime>
    #include <cstdlib>
    #define pii pair<int, int>
    #define mp make_pair
    #define ft first
    #define sd second
    #define ls C[rt][0]
    #define rs C[rt][1]
    using namespace std;
    
    template <typename ty> void read(ty &x) {
      x = 0; int f = 1; char ch = getchar();
      while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
      while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
      x *= f;
    }
    template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; }
    template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; }
    template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; }
    template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; }
    
    typedef long long LL;
    typedef double db;
    
    const int inf = 0x7fffffff;
    const int N = 2e5 + 16;
    
    int F[N], V[N*20], C[N*20][2], D[N*20], RT[N], P[N];
    int n, m, sz, lastans;
    
    void build(int &rt, int l, int r) {
      rt = ++sz;
      if (l == r) { V[rt] = l; return; }
      int mid = l + r >> 1;
      build(C[rt][0], l, mid);
      build(C[rt][1], mid + 1, r);
    }
    
    int find(int rt) { return F[rt] == rt ? rt : F[rt] = find(F[rt]); }
    
    int query(int rt, int l, int r, int pos) {
      if (l == r) return V[rt];
      int mid = l + r >> 1;
      if (pos <= mid) return query(C[rt][0], l, mid, pos);
      else return query(C[rt][1], mid + 1, r, pos);
    }
    
    void change(int &now, int pre, int l, int r, int pos, int v) {
      now = ++sz;
      C[now][0] = C[pre][0]; C[now][1] = C[pre][1];
      if (l == r) { V[now] = v; return; }
      int mid = l + r >> 1;
      if (pos <= mid) change(C[now][0], C[pre][0], l, mid, pos, v);
      else change(C[now][1], C[pre][1], mid + 1, r, pos, v);
    }
    
    int get(int rt, int a) {
      int tmp = a;
      while (true) {
        tmp = query(RT[rt], 1, n, tmp);
        if (query(RT[rt], 1, n, tmp) != tmp)
          a = tmp;
        else return tmp;
      }
    }
    
    void add(int rt, int l, int r, int pos) {
      if (l == r) { D[rt] ++; return; }
      int mid = l + r >> 1;
      if (pos <= mid) add(C[rt][0], l, mid, pos);
      else add(C[rt][1], mid + 1, r, pos);
    }
    
    int main () {
    
      read(n); read(m);
      build(RT[0], 1, n);
    
      for (int i = 1; i <= m; ++ i) {
        F[i] = i;
        int opt, a, b, k;
        read(opt);
        if (opt == 1) {
          read(a); read(b);
          a ^= lastans, b ^= lastans;
          int pre = find(i - 1);
          int tmp1, tmp2;
          tmp1 = get(pre, a);
          tmp2 = get(pre, b);
          if (tmp1 == tmp2) { F[i] = i - 1; continue; }
          if (D[tmp1] > D[tmp2]) swap(tmp1, tmp2);
          change(RT[i], RT[pre], 1, n, tmp1, tmp2);
          if (D[tmp1] == D[tmp2]) add(RT[i], 1, n, tmp2);
        }
        if (opt == 2) {
          read(k);
          k ^= lastans;
          F[i] = find(k);
        }
        if (opt == 3) {
          F[i] = find(i - 1);
          read(a); read(b);
          a ^= lastans, b ^= lastans;
          int tmp, tmp1, tmp2;
          tmp1 = get(F[i], a);
          tmp2 = get(F[i], b);
          if (tmp1 == tmp2) lastans = 1, printf("1
    ");
          else lastans = 0, printf("0
    ");
        }
      }
    
    
      return 0;
    
    }
    
  • 相关阅读:
    71)PHP,使用cookie的语法问题
    70)PHP,cookie的安全传输和HTTPonly
    69)PHP,cookie的有效域
    68)PHP,cookie的详细属性和有效期
    C#中的internal关键字
    C# 中如何将一个类文件(XX.CS)封装成.dll文件
    c# 委托和事件(总结篇)
    c#事件实例三
    c#事件实例二
    c#事件实例一
  • 原文地址:https://www.cnblogs.com/Anding-16/p/8046632.html
Copyright © 2020-2023  润新知