zoukankan      html  css  js  c++  java
  • BZOJ3673/3674:可持久化并查集

    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

    Solution

    板子题……只不过网上有很多假做法。

    具体做法就是整两个可持久化数组(不知道谁起的这么鬼畜的名字……我还是更喜欢叫他可持久化线段树)来记录并查集的$fa$数组和$dep$数组。因为路径压缩会破坏可持久化的结构,所以我们只能记录$dep$数组来按秩合并。

    网上很多只搞了一颗可持久化线段树,维护$fa$就可持久化线段树$insert$一条链,维护$dep$就修改历史版本上的点的做法是错的……已经被卡掉了QAQ

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #define N (200009)
     4 using namespace std;
     5 
     6 int n,m,lastans,opt,x,y;
     7 
     8 struct Tree
     9 {
    10     struct Sgt{int ls,rs,v;}Segt[N*20];
    11     int sgt_num,a[N],Root[N];
    12     int Build(int l,int r)
    13     {
    14         int now=++sgt_num;
    15         if (l==r) {Segt[now].v=a[l]; return now;}
    16         int mid=(l+r)>>1;
    17         Segt[now].ls=Build(l,mid);
    18         Segt[now].rs=Build(mid+1,r);
    19         return now;
    20     }
    21     int Update(int pre,int l,int r,int x,int v)
    22     {
    23         int now=++sgt_num;
    24         Segt[now].ls=Segt[pre].ls;
    25         Segt[now].rs=Segt[pre].rs;
    26         if (l==r) {Segt[now].v=v; return now;}
    27         int mid=(l+r)>>1;
    28         if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x,v);
    29         else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x,v);
    30         return now;
    31     }
    32     int Query(int now,int l,int r,int x)
    33     {
    34         if (l==r) return Segt[now].v;
    35         int mid=(l+r)>>1;
    36         if (x<=mid) return Query(Segt[now].ls,l,mid,x);
    37         else return Query(Segt[now].rs,mid+1,r,x);
    38     }
    39 }CT[2];
    40 
    41 int Find(int x,int t)
    42 {
    43     int fa=CT[0].Query(CT[0].Root[t],1,n,x);
    44     return x==fa?x:Find(fa,t);
    45 }
    46 
    47 int main()
    48 {
    49     scanf("%d%d",&n,&m);
    50     for (int i=1; i<=n; ++i)
    51         CT[0].a[i]=i, CT[1].a[i]=1;
    52     CT[0].Root[0]=CT[0].Build(1,n);
    53     CT[1].Root[0]=CT[1].Build(1,n);
    54     for (int i=1; i<=m; ++i)
    55     {
    56         scanf("%d",&opt);
    57         if (opt==1)
    58         {
    59             CT[0].Root[i]=CT[0].Root[i-1];
    60             CT[1].Root[i]=CT[1].Root[i-1];
    61             scanf("%d%d",&x,&y);
    62             /*x^=lastans; y^=lastans;*/
    63             int fx=Find(x,i),fy=Find(y,i);
    64             if (fx==fy) continue;
    65             int dfx=CT[1].Query(CT[1].Root[i],1,n,fx);
    66             int dfy=CT[1].Query(CT[1].Root[i],1,n,fy);
    67             if (dfx>dfy) swap(fx,fy);
    68             CT[0].Root[i]=CT[0].Update(CT[0].Root[i],1,n,fx,fy);
    69             if (dfx!=dfy) continue;
    70             CT[1].Root[i]=CT[1].Update(CT[1].Root[i],1,n,fy,dfy+1);
    71         }
    72         if (opt==2)
    73         {
    74             scanf("%d",&x); /*x^=lastans;*/
    75             CT[0].Root[i]=CT[0].Root[x];
    76             CT[1].Root[i]=CT[1].Root[x];
    77         }
    78         if (opt==3)
    79         {
    80             CT[0].Root[i]=CT[0].Root[i-1];
    81             CT[1].Root[i]=CT[1].Root[i-1];
    82             scanf("%d%d",&x,&y);
    83             /*x^=lastans; y^=lastans;*/
    84             int fx=Find(x,i),fy=Find(y,i);
    85             if (fx==fy) puts("1")/*, lastans=1*/;
    86             else puts("0")/*, lastans=0*/;
    87         }
    88     }
    89 }
  • 相关阅读:
    C文件读写函数介绍(转)
    字节存储排序:大端和小端的判别及转换
    vc++上的MFC的对象序列化和反序列化
    unicode下各种类型转换,CString,string,char*,int,char[]
    CString与std::string unicode下相互转化
    VS2010每次编译都重新编译整个工程的解决方案
    Windows下用C语言获取进程cpu使用率,内存使用,IO情况
    hadoop 安装
    python---pyc pyo文件详解
    C 高级编程 2 内存管理
  • 原文地址:https://www.cnblogs.com/refun/p/10230348.html
Copyright © 2011-2022 走看看