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

    Time Limit: 5 Sec Memory Limit: 128 MB

    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

    用可持久化线段树来可持久化数组以达到可持久化并查集的作用,有点像绕口令。。。

    要注意的就是并查集的find也要在树上找到那个位置,使用它的位置,所以复杂度应该是两个log的,n logn logn 一次AC

     1 #include<bits/stdc++.h>
     2 #define maxn 20005
     3 #define mae 800005
     4 using namespace std;
     5 int n,m,root[maxn],l[mae],r[mae],cnt,fa[mae],rank[mae],L[mae],R[mae];
     6 void build(int& k,int le,int ri){
     7     if(!k) k=++cnt;L[k]=le;R[k]=ri;
     8     if(le==ri){fa[k]=le;rank[k]=0;return;}
     9     int mid=le+ri>>1;
    10     build(l[k],le,mid);build(r[k],mid+1,ri);
    11 }
    12 void newly(int &k,int wi,int f,int h){
    13     k=++cnt;
    14     L[k]=L[wi];R[k]=R[wi];
    15     if(L[k]==R[k]){fa[k]=h;return;}
    16     l[k]=l[wi];r[k]=r[wi];
    17     int mid=L[k]+R[k]>>1;
    18     if(f<=mid) newly(l[k],l[wi],f,h);
    19     else newly(r[k],r[wi],f,h);
    20 }
    21 int find(int k,int x){
    22     if(L[k]==R[k]) return k;
    23     int mid=L[k]+R[k]>>1;
    24     if(x<=mid) return find(l[k],x);
    25     else return find(r[k],x);
    26 }
    27 int fi(int x,int k){
    28     k=find(root[x],k);
    29     if(fa[k]!=L[k]) return fi(x,fa[k]);
    30     return fa[k];
    31 }
    32 int main(){
    33     scanf("%d%d",&n,&m);
    34     build(root[0],1,n);int a,b,c,f,h;
    35     for(int i=1;i<=m;i++){
    36         scanf("%d",&a);
    37         if(a==1){
    38             scanf("%d%d",&b,&c);
    39             f=fi(i-1,b);h=fi(i-1,c);
    40             if(rank[f]<rank[h]) newly(root[i],root[i-1],f,h);
    41             else{
    42                 if(rank[f]>rank[h]) newly(root[i],root[i-1],h,f);
    43                 else {newly(root[i],root[i-1],f,h);rank[find(root[i],f)]++;}
    44             }
    45         }
    46         if(a==2) scanf("%d",&b),root[i]=root[b];
    47         if(a==3){
    48             scanf("%d%d",&b,&c);root[i]=root[i-1];
    49             f=fi(i,b);h=fi(i,c);
    50             if(f==h) printf("1
    ");
    51             else printf("0
    ");
    52         }
    53     }
    54     return 0;
    55 }

  • 相关阅读:
    SecureRandom
    一个不错的架构图:基于SpringCloud的微服务项目
    Android 增量更新完全解析 是增量不是热修复
    Android热修复方案比较
    Android Activity作为dialog对话框的使用详细介绍
    Android 微信分享不出去?四步搞定!
    Android:用签名打包后微信分享失效
    Android 根据QQ号跳转到QQ聊天界面
    Android fragment-findFragmentByTag 始终返回 null
    Android RecyclerView遇到notifyDataSetChanged无效时的解决方案
  • 原文地址:https://www.cnblogs.com/awipppp/p/5959517.html
Copyright © 2011-2022 走看看