zoukankan      html  css  js  c++  java
  • 【BZOJ3673】【可持久化并查集】可持久化并查集 by zky

    Description

    n个集合 m个操作
    操作:
    1 a b 合并a,b所在集合
    2 k 回到第k次操作之后的状态(查询算作操作)
    3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

    0<n,m<=2*10^4

    Input

     

    Output

     

    Sample Input

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

    Sample Output

    1
    0
    1

    HINT

    Source

    出题人大S

    【分析】

    出题人给我滚出来!保证不打死你!

    真是***了,你题意描述清楚点会死啊。。调了将近2个小时...结果是题目理解错了....尼玛返回也算作操作啊。

    思路还是蛮简单的。

    用主席树维护一下并查集的fa数组就行了。

    按照这种说法树状数组也应该可以可持久化了

      1 /*
      2 唐代李商隐
      3 《无题·昨夜星辰昨夜风》
      4 
      5 昨夜星辰昨夜风,画楼西畔桂堂东。
      6 身无彩凤双飞翼,心有灵犀一点通。
      7 隔座送钩春酒暖,分曹射覆蜡灯红。
      8 嗟余听鼓应官去,走马兰台类转蓬。
      9 */
     10 #include <iostream>
     11 #include <cstdio>
     12 #include <algorithm>
     13 #include <cstring>
     14 #include <vector>
     15 #include <utility>
     16 #include <iomanip>
     17 #include <string>
     18 #include <cmath>
     19 #include <queue>
     20 #include <assert.h>
     21 #include <map>
     22 #include <ctime>
     23 #include <cstdlib>
     24 #include <stack>
     25 #define LOCAL
     26 const int MAXN = 20000 * 10 * 20 + 10;
     27 //const int MAXM = 20000 + 10;
     28 const int INF = 100000000;
     29 const int SIZE = 450;
     30 const int maxnode =  0x7fffffff + 10;
     31 using namespace std;
     32 int n, m;//n为元素总个数 
     33 struct SEGTREE{
     34        //路径压缩+启发式合并还要用主席树OAO 
     35        struct Node{
     36               Node *ch[2];
     37               int l, r;
     38               int num;//其实除了叶子节点其他都是打酱油的,num是该节点的fa值 
     39        }mem[MAXN], *root[200000 * 10 + 10];
     40        int tot;
     41        
     42        void init(){
     43             tot = 0;
     44             root[0] = NULL;
     45             for (int i = 1; i <= 200000 * 10; i++) root[i] = NULL;
     46             build(root[0], 1, n);
     47             //printf("%d %d
    ", root[0]->ch[0]->l, root[0]->ch[0]->r);
     48        }
     49        Node *NEW(int l, int r){
     50             Node *p = &mem[tot++];
     51             p->l = l;
     52             p->r = r;
     53             p->num = -1;
     54             p->ch[0] = p->ch[1] = NULL;
     55             return p;
     56        } 
     57        void build(Node *&t, int l, int r){
     58             if (t == NULL){
     59                   t = NEW(l, r);
     60                   //不要返回 
     61             }
     62             if (l == r) return;
     63             int mid = (l + r) >> 1;
     64             build(t->ch[0], l, mid);
     65             build(t->ch[1], mid + 1, r);
     66        }
     67        //t为现在的数将x的num改为val 
     68        void insert(Node *&t, Node *&last, int x, int val){
     69             if (t == NULL){
     70                t = NEW(last->l, last->r);
     71             }
     72             if (t->l == x && t->r == x) {t->num = val; return;}
     73             int mid = (t->l + t->r) >>1;
     74             if (x <= mid){
     75                   insert(t->ch[0], last->ch[0], x, val);
     76                   t->ch[1] = last->ch[1];
     77             }
     78             if (x > mid){
     79                   insert(t->ch[1], last->ch[1], x, val);
     80                   t->ch[0] = last->ch[0];
     81             }
     82        }
     83        //直接修改,不是可持久化的,节省空间 
     84        /*void change(Node *&t, int x, int val){
     85             if (t->l == x && t->r == x) {t->num = val;return;}
     86             int mid = (t->l + t->r) >> 1;
     87             if (x <= mid) change(t->ch[0], x, val);
     88             if (x > mid) change(t->ch[1], x, val);
     89        }*/
     90        int get(int k, int x){//查找k时刻x的fa值 
     91            Node *t = root[k];
     92            while (1){
     93                  if (t->l == x && t->r == x) break;
     94                  int mid = (t->l + t->r) >> 1;
     95                  if (x <= mid) t = t->ch[0];
     96                  else t = t->ch[1];
     97            }
     98            return t->num;
     99        }
    100 }A;
    101 int data[MAXN];//真正的操作次数 
    102 int cnt = 0;//cnt记录现在的状态 
    103 int BIGCNT;
    104 
    105 int find(int x){
    106     int tmp = A.get(cnt, x);
    107     if (tmp < 0) return x;
    108     else{
    109          int tmp2 = find(tmp);
    110          //A.insert(A.root[cnt + 1], A.root[cnt], x, tmp2);
    111          //cnt++;
    112          return tmp2;
    113     }
    114 }
    115 //启发式合并 
    116 void merge(int x, int y){
    117     //分别代表真实数量 
    118     int x_num = -A.get(cnt, x);
    119     int y_num = -A.get(cnt ,y);
    120     if (x_num > y_num){//将y合并到x上 
    121        //这里可以可持久化了 
    122        //A.root[cnt + 1] = NULL;
    123        A.insert(A.root[BIGCNT + 1], A.root[cnt], x, -(x_num + y_num));
    124        BIGCNT++;
    125        //A.root[cnt + 1] = NULL;
    126        A.insert(A.root[BIGCNT + 1], A.root[cnt], y, x);
    127        BIGCNT++;
    128     }else{
    129        //A.root[cnt + 1] = NULL;
    130        A.insert(A.root[BIGCNT + 1], A.root[cnt], y, -(x_num + y_num));
    131        BIGCNT++;
    132        //A.root[cnt + 1] = NULL;
    133        A.insert(A.root[BIGCNT + 1], A.root[cnt], x, y);
    134        BIGCNT++;
    135        //printf("%d %d %d
    ", x, y, find(x));
    136     }
    137 }
    138 void work(){
    139      int z = 1;//记录操作的
    140      data[0] = 0; 
    141      cnt = 0;
    142      BIGCNT = 0;
    143      scanf("%d%d", &n, &m); 
    144      A.init();
    145      for (int i = 1; i <= m; i++){
    146          int t;
    147          scanf("%d", &t);
    148          if (t == 2){
    149             int c;
    150             scanf("%d", &c);//回到c时刻即操作之后 
    151             if (c == 2)
    152             printf("");
    153             cnt = data[c];
    154          }else if (t == 1){
    155             int a, b;
    156             scanf("%d%d", &a, &b);
    157             int xa = find(a), xb = find(b);
    158             if (xa == xb) {data[i] = cnt;continue;}
    159             merge(xa, xb);
    160             cnt = BIGCNT;
    161          }else{
    162             int a, b;
    163             scanf("%d%d", &a, &b);
    164             if (find(a) == find(b)) printf("1
    ");
    165             else printf("0
    "); 
    166          } 
    167          data[i] = cnt;
    168      }
    169      //printf("%d", data[6]);
    170 }
    171 
    172 int main(){
    173     
    174    
    175     work();
    176     return 0;
    177 }
    View Code
  • 相关阅读:
    20、职责链模式
    19、命令模式
    18、桥接模式
    17、单例模式
    javascript移动端实现企业图谱总结
    前端用js模拟疫情扩散开发总结
    移动端企业图谱开发兼容性等问题踩坑
    js实现企业图谱(pc端企业图谱项目总结与踩坑分享)
    基于vue脚手架的项目打包上线(发布)方法和误区
    实现一个网页版的聊天室(类似于钉钉群)
  • 原文地址:https://www.cnblogs.com/hoskey/p/4335344.html
Copyright © 2011-2022 走看看