• 数据结构:可持久化并查集


    在基础并查集上改良,让并查集支持回滚到历史版本

    这里介绍一下普通并查集的两种优化,一个是路径压缩,一个是按秩合并(启发式合并)

    路径压缩是在find上动手脚,让查询经过的点都直接与根相连,这样下次再查的时候复杂度就可以是O(1)

    按秩合并是在union上动手脚,合并时让小集合拼接到较大集合上面,集合的大小用deep来衡量,这样就可以近似得到O(logn)的复杂度

    在实现可持久化的时候,加上路径压缩会慢,只需要用按秩合并优化就好了

    但是对于普通并查集来说,路径压缩就已经相当快了

    其实并查集就是一个fa数组,那么可持久化并查集就是让这个数组更高级一些就可以了

    多高级呢?支持单点修改和历史版本查询的数组

    具体的做法是开一个可持久化线段树(可持久化线段树的思想在主席树里有介绍)

    这棵线段树的非叶子节点i只负责维护lson和rson,不维护除此之外的任何信息

    它的作用是方便我们在修改的时候快速地将[Li,Ri]这一段O(1)地指向它的历史版本

    使用启发式合并

    这样找一个节点所在集合的根,就需要查询log(n)次线段树

    而每一次时间都是log(n),故时间为O(m*log^2(n)),空间为m*log(n)

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=200005;
     5 const int maxm=200005;
     6 int n,m,sz,last;
     7 int root[maxm],lch[10000005],rch[10000005],v[10000005],deep[10000005];
     8 inline int read()
     9 {
    10     int x=0;char ch=getchar();
    11     while(ch>'9'||ch<'0') ch=getchar();
    12     while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    13     return x;
    14 }
    15 void build(int &k,int l,int r)
    16 {
    17     if(k==0) k=++sz;
    18     if(l==r) {v[k]=l;return;}
    19     int mid=(l+r)>>1;
    20     build(lch[k],l,mid);
    21     build(rch[k],mid+1,r);
    22 }
    23 void modify(int l,int r,int x,int &y,int pos,int val)
    24 {
    25     y=++sz;
    26     if(l==r) {v[y]=val;deep[y]=deep[x];return;}
    27     lch[y]=lch[x];rch[y]=rch[x];
    28     int mid=(l+r)>>1;
    29     if(pos<=mid)
    30         modify(l,mid,lch[x],lch[y],pos,val);
    31     else modify(mid+1,r,rch[x],rch[y],pos,val);
    32 }
    33 int query(int k,int l,int r,int pos)
    34 {
    35     if(l==r) return k;
    36     int mid=(l+r)>>1;
    37     if(pos<=mid) return query(lch[k],l,mid,pos);
    38     else return query(rch[k],mid+1,r,pos);
    39 }
    40 void add(int k,int l,int r,int pos)
    41 {
    42     if(l==r) {deep[k]++;return;}
    43     int mid=(l+r)>>1;
    44     if(pos<=mid) add(lch[k],l,mid,pos);
    45     else add(rch[k],mid+1,r,pos);
    46 }
    47 int find(int k,int x)
    48 {
    49     int p=query(k,1,n,x);
    50     if(x==v[p]) return p;
    51     return find(k,v[p]);
    52 }
    53 int main()
    54 {
    55     n=read();m=read();
    56     build(root[0],1,n);
    57     int f,k,a,b;
    58     for(int i=1;i<=m;i++)
    59     {
    60         f=read();
    61         if(f==1)
    62         {
    63             root[i]=root[i-1];
    64             a=read();b=read();a=a^last;b=b^last;
    65             int p=find(root[i],a),q=find(root[i],b);
    66             if(v[p]==v[q]) continue;
    67             if(deep[p]>deep[q]) swap(p,q);
    68             modify(1,n,root[i-1],root[i],v[p],v[q]);
    69             if(deep[p]==deep[q]) add(root[i],1,n,v[q]);
    70         }
    71         if(f==2)
    72         {
    73             k=read();k=k^last;root[i]=root[k];
    74         }
    75         if(f==3)
    76         {
    77             root[i]=root[i-1];
    78             a=read();b=read();a=a^last;b=b^last;
    79             int p=find(root[i],a),q=find(root[i],b);
    80             if(v[p]==v[q]) last=1;
    81             else last=0;
    82             printf("%d
    ",last);
    83         }
    84     }
    85 }

    仔细观察主席树和带修主席树的代码,可以发现有的地方是一致的

    这里的add是改秩

  • 相关阅读:
    Key-Value Memory Network
    Deep Mask Memory Network with Semantic Dependency and Context Moment for Aspect Level Sentiment Clas
    Deep Memory Network在Aspect Based Sentiment方向上的应用
    Deep Memory Network 深度记忆网络
    Self Attention 自注意力机制
    Attention基本公式及其变种
    *端策略优化算法(PPO)
    Policy Gradient 算法
    一本通 农场派对
    A
  • 原文地址:https://www.cnblogs.com/aininot260/p/9518216.html
Copyright © 2020-2023  润新知