zoukankan      html  css  js  c++  java
  • 可持久化并(xian)查(duan)集(shu)

    随便地点开了这道可持久化并查集,发现了真相...这和并查集有 PI 关系哦.除了find_father(而且还不能路径压缩),全都是线段树0.0

    题目链接: luogu.org

    题目没什么描述,就是三个操作:

    1. 合并 a b

    2. 回到第 k 步操作(三个操作均算操作)

    3. 查询 a b 在当前版本的并查集中是否在同一棵树中

    那么...

    对于操作 1 :我们在线段树中修改节点 fa 的父亲为 fb


    对于操作 2 :简单,我们直接把当前版本的根指向第 k 版本的根,一行就解决了(引起可持久化的罪魁祸首解决倒是简单)

    对于操作 3 :查询 fafb 输出就好了(貌似就操作 1 有点不好理解

    对于操作 1 ,模拟如图:

     

    代码如下:

     1 //by Judge
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #define ls ch[now][0]
     7 #define rs ch[now][1]
     8 #define mid (l+r>>1)
     9 #define swap(a,b)  (a)^=(b)^=(a)^=(b)
    10 using namespace std;
    11 const int M=2e5+11; 
    12 inline int read(){
    13     int x=0,f=1; char c=getchar();
    14     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    15     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    16     return x*f;
    17 }
    18 int n,m,cnt;
    19 int ed[M<<5],f[M<<5],ch[M<<5][2],dep[M<<5];
    20 inline void build(int& now,int l,int r){  //建树,叶子节点认 左(右)端点 为父亲
    21     now=++cnt; if(l==r){ f[now]=l; return ; }
    22     build(ls,l,mid), build(rs,mid+1,r);
    23 }
    24 void update(int& now,int las,int l,int r,int pos,int fa){  //修改 pos 的父亲为 fa
    25     now=++cnt; if(l==r){ f[now]=fa,dep[now]=dep[las]; return ; }
    26     if(pos<=mid) update(ls,ch[las][0],l,mid,pos,fa);
    27     else update(rs,ch[las][1],mid+1,r,pos,fa);
    28 }
    29 int query(int now,int l,int r,int pos){  //询问在 now 版本中 pos 的节点编号
    30     if(l==r) return now;
    31     if(pos<=mid) return query(ls,l,mid,pos);
    32     else return query(rs,mid+1,r,pos);
    33 }
    34 void add(int now,int l,int r,int pos){ //增加 now 版本中 pos 所在叶子节点的深度
    35     if(l==r) { ++dep[now]; return ; }
    36     if(pos<=mid) add(ls,l,mid,pos);
    37     else add(rs,mid+1,r,pos);
    38 }
    39 int find(int ed,int x){  //查询祖先
    40     int fa=query(ed,1,n,x);
    41     if(x==f[fa]) return fa;
    42     return find(ed,f[fa]);
    43 }
    44 int main(){
    45     n=read(),m=read(),build(ed[0],1,n);
    46     for(int i=1,opt,a,b,f1,f2;i<=m;++i)
    47         switch(opt=read()){
    48             case 1:  //不显然
    49                 ed[i]=ed[i-1],a=read(),b=read();
    50                 f1=find(ed[i],a),f2=find(ed[i],b);
    51                 if(f[f1]==f[f2]) break;
    52                 if(dep[f1]>dep[f2]) swap(f1,f2);
    53                 update(ed[i],ed[i-1],1,n,f[f1],f[f2]);
    54                 if(dep[f1]==dep[f2]) add(ed[i],1,n,f[f2]); break; //这里 emmm,看上文
    55             case 2: //显然
    56                 ed[i]=ed[read()]; break;
    57             case 3:  //显然
    58                 ed[i]=ed[i-1],a=read(),b=read();
    59                 f1=find(ed[i],a), f2=find(ed[i],b);
    60                 puts(f[f1]==f[f2]?"1":"0"); break;
    61         }
    62     return 0;
    63 }

    上面代码可能出锅,下面代码应该没毛病...

     1 //by Judge
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #define ls ch[now][0]
     7 #define rs ch[now][1]
     8 #define mid (l+r>>1)
     9 #define swap(a,b)  (a)^=(b)^=(a)^=(b)
    10 using namespace std;
    11 const int M=2e5+11; 
    12 inline int read(){
    13     int x=0,f=1; char c=getchar();
    14     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    15     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    16     return x*f;
    17 }
    18 int n,m,cnt;
    19 int ed[M<<5],f[M<<5],ch[M<<5][2],dep[M<<5];
    20 inline void build(int& now,int l,int r){
    21     now=++cnt; if(l==r){ f[now]=l; return ; }
    22     build(ls,l,mid), build(rs,mid+1,r);
    23 }
    24 void update(int& now,int las,int l,int r,int pos,int fa){
    25     now=++cnt; if(l==r){ f[now]=fa,dep[now]=dep[las]; return ; }
    26     ls=ch[las][0], rs=ch[las][1];
    27     if(pos<=mid) update(ls,ch[las][0],l,mid,pos,fa);
    28     else update(rs,ch[las][1],mid+1,r,pos,fa);
    29 }
    30 int query(int now,int l,int r,int pos){
    31     if(l==r) return now;
    32     if(pos<=mid) return query(ls,l,mid,pos);
    33     else return query(rs,mid+1,r,pos);
    34 }
    35 void add(int now,int l,int r,int pos){
    36     if(l==r) { ++dep[now]; return ; }
    37     if(pos<=mid) add(ls,l,mid,pos);
    38     else add(rs,mid+1,r,pos);
    39 }
    40 int find(int ed,int x){
    41     int fa=query(ed,1,n,x);
    42     if(x==f[fa]) return fa;
    43     return find(ed,f[fa]);
    44 }
    45 int main(){
    46     n=read(),m=read(),build(ed[0],1,n);
    47     for(int i=1,opt,a,b,f1,f2;i<=m;++i)
    48         switch(opt=read()){
    49             case 1:
    50                 ed[i]=ed[i-1],a=read(),b=read();
    51                 f1=find(ed[i],a),f2=find(ed[i],b);
    52                 if(f[f1]==f[f2]) break;
    53                 if(dep[f1]>dep[f2]) swap(f1,f2);
    54                 update(ed[i],ed[i-1],1,n,f[f1],f[f2]);
    55                 if(dep[f1]==dep[f2]) add(ed[i],1,n,f[f2]); break;
    56             case 2: ed[i]=ed[read()]; break;
    57             case 3:
    58                 ed[i]=ed[i-1],a=read(),b=read();
    59                 f1=find(ed[i],a), f2=find(ed[i],b);
    60                 puts(f[f1]==f[f2]?"1":"0"); break;
    61         }
    62     return 0;
    63 }

     by Judge

  • 相关阅读:
    史蒂夫·乔布斯-读书笔记3
    史蒂夫·乔布斯-读书笔记2
    史蒂夫·乔布斯-读书笔记1
    Mac配置Qt环境——Could not resolve SDK path for 'macosx10.8'
    相信
    搞笑语录 一
    C++ 引用
    C++ inline函数
    AI-随机迷宫&迷宫求解
    sizeof && strlen 的区别
  • 原文地址:https://www.cnblogs.com/Judge/p/9441179.html
Copyright © 2011-2022 走看看