平衡树

splay

普通平衡树

#include<bits/stdc++.h> 
using namespace std;
const int MAX=101000;
char opt;
int mi,sum,sm=MAX,num;
int son[MAX][2],val[MAX],fa[MAX],siz[MAX],cnt[MAX],tot,root,x,n;
inline bool Dir(int x){return val[x]>val[fa[x]];}
void pushup(int x){ siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; }
inline void rotate(int x){
    int y=fa[x],z=fa[y],k=Dir(x),w=son[x][k^1];
    son[z][Dir(y)]=x;fa[x]=z;
    son[x][k^1]=y;fa[y]=x;
    son[y][k]=w;fa[w]=y;
    pushup(y);pushup(x);//现在y是儿子,x是父亲 
}
inline void splay(int x,int goal=0){
    while(fa[x]!=goal){
        int y=fa[x],z=fa[y];
        if(z!=goal){
            if(Dir(x)==Dir(y))  rotate(y);
            else rotate(x);
        }rotate(x);
    }if(!goal)  root=x;
    //cout<<x<<" "<<siz[root]<<endl;
} 
inline void find(int x){
    if(!root)  return;
    int cur=root;
    while(son[cur][x>val[cur]]&&val[cur]!=x)
        cur=son[cur][x>val[cur]];
    splay(cur);
}
inline void ins(int x){
    int cur=root,p=0;
    while(cur&&val[cur]!=x)
        p=cur,cur=son[cur][x>val[cur]];
    if(cur) cnt[cur]++;
    else{
        cur=++tot;
        if(p) son[p][x>val[p]]=cur;
        son[cur][0]=son[cur][1]=0;
        val[cur]=x;fa[cur]=p;
        cnt[cur]=siz[cur]=1;
    }splay(cur);
            //cout<<x<<" "<<cur<<endl;
} 
inline int las(int x){
    find(x);
    if(val[root]<x)  return root;
    int cur=son[root][0];
    while(son[cur][1])  cur=son[cur][1];
    splay(cur);return cur;
}
inline int nex(int x){
    find(x);
    if(val[root]>x)  return root;
    int cur=son[root][1];
    while(son[cur][0])  cur=son[cur][0];
    splay(cur);return cur;
}
inline void del(int x){
    int l=las(x),r=nex(x);//
    splay(l);splay(r,l);
    int d=son[r][0];
    if(cnt[d]>1){cnt[d]--;splay(d);}
    else son[r][0]=0;
    pushup(r);pushup(root);
} 
inline int getrk1(int x){
    find(x);
    return siz[son[root][1]]+(val[root]>=x?cnt[root]:0); 
} 
inline int getrk(int x){
    find(x);
    return siz[son[root][0]]+(val[root]<x?cnt[root]:0); 
} 
inline int getth(int k){
    int cur=root;
    while(1){
        if(k<=siz[son[cur][1]]&&son[cur][1])
            cur=son[cur][1];
        else
            if(k>siz[son[cur][1]]+cnt[cur]){
                k-=siz[son[cur][1]]+cnt[cur];
                cur=son[cur][0];
            }
            else{splay(cur);return val[cur];}
    } 
}
View Code

 艺术平衡树

#include<bits/stdc++.h>
using namespace std;
const int MAX=100010;
int son[MAX][2],siz[MAX],val[MAX],fa[MAX],laz[MAX],tot,root,m,n,x,a[MAX];
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
inline bool Dir(int x){return x==son[fa[x]][1];}//val[x]>val[fa[x]]不具有左小右大 
inline void pushup(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}
inline void pushdown(int x){
    if(x&&laz[x]){
        laz[son[x][0]]^=1;laz[son[x][1]]^=1;
        swap(son[x][0],son[x][1]);laz[x]=0;
    }
}
int build(int f,int l,int r){
    if(l>r)  return 0;
    int mid=(l+r)>>1,cur=++tot;
    son[cur][0]=son[cur][1]=0;
    val[cur]=a[mid];fa[cur]=f;laz[cur]=0;//cur
    son[cur][0]=build(cur,l,mid-1);//避开重复祖先 
    son[cur][1]=build(cur,mid+1,r);    
    pushup(cur);return cur;
}
void write(int x){
    pushdown(x);
    if(son[x][0])  write(son[x][0]);
    if(abs(val[x])!=INT_MAX)  printf("%d ",val[x]);
    if(son[x][1])  write(son[x][1]);
}
inline void rotate(int x){
    int y=fa[x],z=fa[y],k=Dir(x),w=son[x][k^1];
    pushdown(y);pushdown(x);
    son[z][Dir(y)]=x;fa[x]=z;
    son[x][k^1]=y;fa[y]=x;
    son[y][k]=w;fa[w]=y;
    pushup(y),pushup(x);
}
inline void splay(int x,int goal=0){
    while(fa[x]!=goal){
        int y=fa[x],z=fa[y];
        if(z!=goal){
            if(Dir(x)==Dir(y))  rotate(y);
            else  rotate(x);
        }rotate(x);
    }if(!goal)  root=x; 
}
inline int getth(int k){
    int cur=root;
    while(1){
        pushdown(cur);
        if(k>siz[son[cur][0]]){
            k-=siz[son[cur][0]]+1;
            if(!k)  return cur;
            cur=son[cur][1];
        }else  cur=son[cur][0];
    }
}
inline void turn(int l,int r){
    l=getth(l);r=getth(r+2);
    splay(l);splay(r,l);
    laz[son[son[root][1]][0]]^=1;
}
int main(){
    n=read();m=read();
    a[1]=-INT_MAX;a[n+2]=INT_MAX;
    for(int i=2;i<=n+1;++i)  a[i]=i-1;
    root=build(0,1,n+2);
    for(int i=1;i<=m;++i){int l=read(),r=read();turn(l,r);}
    write(root);
}
View Code

 二逼平衡树

#include<bits/stdc++.h>
using namespace std;
const int MAX=50010<<5;
int k,mi=INT_MAX,ma=-INT_MAX;
int son[MAX][2],siz[MAX],val[MAX],fa[MAX],cnt[MAX],tot,root[MAX],m,n,x,a[MAX],opt,l,r;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
void build(int,int,int);
int query1(int,int,int,int,int,int);
int query2(int,int,int,int,int,int);
int query3(int,int,int,int,int,int);
void update(int,int,int,int,int);
inline bool Dir(int x){return val[x]>val[fa[x]];}
void pushup(int x){ siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; }
inline void rotate(int x){
    int y=fa[x],z=fa[y],k=Dir(x),w=son[x][k^1];
    son[z][Dir(y)]=x;fa[x]=z;
    son[x][k^1]=y;fa[y]=x;
    son[y][k]=w;fa[w]=y;
    pushup(y);pushup(x);
}
inline void splay(int pos,int x,int goal=0){
    while(fa[x]!=goal){
        int y=fa[x],z=fa[y];
        if(z!=goal){
            if(Dir(x)==Dir(y))  rotate(y);
            else rotate(x);
        }rotate(x);
    }if(!goal)  root[pos]=x;
} 
inline void ins(int pos,int x){
    int cur=root[pos],p=0;
    while(cur&&val[cur]!=x)
        p=cur,cur=son[cur][x>val[cur]];
    if(cur)  cnt[cur]++;
    else{
        cur=++tot;son[p][x>val[p]]=cur;
        val[cur]=x;fa[cur]=p;
        cnt[cur]=siz[cur]=1;
    }splay(pos,cur);
}
inline void find(int pos,int x){
    int cur=root[pos];
    while(son[cur][x>val[cur]]&&val[cur]!=x)
        cur=son[cur][x>val[cur]];
    splay(pos,cur);
}
inline int getrk(int pos,int x){
    find(pos,x);
    return siz[son[root[pos]][0]]+(val[root[pos]]<x?cnt[root[pos]]:0); 
} 
inline int las(int pos,int x){
    find(pos,x);
    if(val[root[pos]]<x)  return root[pos];
    int cur=son[root[pos]][0];
    while(son[cur][1])  cur=son[cur][1];
    splay(pos,cur);return cur;
}
inline int nex(int pos,int x){
    find(pos,x);
    if(val[root[pos]]>x)  return root[pos];
    int cur=son[root[pos]][1];
    while(son[cur][0])  cur=son[cur][0];
    splay(pos,cur);return cur;
}
inline void del(int pos,int x){
    int l=las(pos,x),r=nex(pos,x);
    splay(pos,l);splay(pos,r,l);
    int d=son[r][0];
    if(cnt[d]>1){cnt[d]--;splay(pos,d);}
    else son[r][0]=0;
    pushup(r);pushup(root[pos]);
} 
int main(){
    n=read();m=read();
    for(int i=1;i<=n;++i)  a[i]=read(),mi=min(mi,a[i]),ma=max(ma,a[i]);
    build(1,1,n);
    for(int i=1;i<=m;++i){
        opt=read();
        if(opt==1){
            l=read();r=read();x=read();
            printf("%d\n",query1(1,1,n,l,r,x)+1);
        }
        if(opt==2){
            l=read();r=read();k=read();
            int ll=mi,rr=ma,ans;
            while(ll<rr){
                int mid=(ll+rr)>>1;
                int rk=query1(1,1,n,l,r,mid)+1,r1=query1(1,1,n,l,r,mid+1);
                if(rk<=k&&r1>=k){ans=mid;break;}
                if(rk>k)  rr=mid;
                else  ll=mid+1;
            }printf("%d\n",ans);
        }
        if(opt==3){
            k=read();x=read();
            mi=min(mi,x);ma=max(ma,x);
            update(1,1,n,k,x);
        }
        if(opt==4){
            l=read();r=read();x=read();
            printf("%d\n",query2(1,1,n,l,r,x));
        }
        if(opt==5){
            l=read();r=read();x=read();
            printf("%d\n",query3(1,1,n,l,r,x));
        }
    }
}
void build(int pos,int l,int r){
    if(r<l)  return;
    ins(pos,-INT_MAX);ins(pos,INT_MAX);
    for(int i=l;i<=r;++i)  ins(pos,a[i]);
    if(l==r) return;
    int mid=(l+r)>>1;
    build(pos<<1,l,mid);build(pos<<1|1,mid+1,r);
}
int query1(int pos,int l,int r,int ll,int rr,int x){
    if(l>rr||r<ll)  return 0;
    if(ll<=l&&r<=rr)  return getrk(pos,x)-1;
    int mid=(l+r)>>1;
    return query1(pos<<1,l,mid,ll,rr,x)+query1(pos<<1|1,mid+1,r,ll,rr,x);
}
void update(int pos,int l,int r,int k,int x){
    if(k<l||k>r)  return;
    del(pos,a[k]);ins(pos,x);
    if(l==r){a[k]=x;return;}
    int mid=(l+r)>>1;
    if(k<=mid)  update(pos<<1,l,mid,k,x);
    else  update(pos<<1|1,mid+1,r,k,x);
}
int query2(int pos,int l,int r,int ll,int rr,int x){
    if(l>rr||r<ll)  return -INT_MAX;
    if(ll<=l&&r<=rr)  return val[las(pos,x)]; 
    int mid=(l+r)>>1;
    return max(query2(pos<<1,l,mid,ll,rr,x),query2(pos<<1|1,mid+1,r,ll,rr,x));
}
int query3(int pos,int l,int r,int ll,int rr,int x){
    if(l>rr||r<ll)  return INT_MAX;
    if(ll<=l&&r<=rr)  return val[nex(pos,x)];
    int mid=(l+r)>>1;
    return min(query3(pos<<1,l,mid,ll,rr,x),query3(pos<<1|1,mid+1,r,ll,rr,x));
}
View Code

treap

旋转

#include<bits/stdc++.h>
using namespace std;
#define ls son[cur][0]
#define rs son[cur][1]
const int MAX=100010;
int n,x,opt;
int rd[MAX],son[MAX][2],siz[MAX],cnt[MAX],val[MAX],root,tot;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
inline int rand(){
    static int seed=2007;
    return seed=(int)((((seed^213)+130183)*1583098ll)%14585428ll);
}
inline void pushup(int cur){siz[cur]=siz[ls]+siz[rs]+cnt[cur];}
inline void rotate(int &x,int dir){
    int r=son[x][dir];son[x][dir]=son[t][dir^1];
    son[t][dir^1]=x;pushup(x);pushup(t);x=t;
}
void ins(int &cur,int x){
    if(!cur){
        cur=++tot;siz[cur]=cnt[cur]=1;
        val[cur]=x;rn[cur]=rand();return;
    }siz[cur]++;
    if(val[cur]==x)  cnt[cur]++;
    else  if(x>val[cur]){
            ins(rs,x);
            if(rn[rs]<rn[cur])  rotate(cur,(x>val[cur]));
    }else{
        ins(ls,x);
        if(rn[ls<rn[cur]])  rotate(cur,(x>val[cur]));
    }
}
void del(int &cur,int x){
    if(!cur)  return;
    if(val[cur]==x){
        if(cnt[cur]>1)  cnt[cur]--,siz[cur]--;
        else{
            if((!ls)||(!rs))  cur=ls+rs;
            else  rotate(cur,(ls>=rs)),dal(cur,x);
        }
    }else  siz[cur]--,del(son[cur][x>val[cur]],x);
}
int getrk(int x){
    int cur=root,ans=0;
    while(cur){
        if(x<val[cur])  cur=ls;
        else  if(x>val[cur]){
            ans+=siz[ls]+cnt[cur];cur=rs;
        }else  return ans+siz[ls]+1;
    }return ans+1;
}
int getth(int k){
    int cur=root;
    while(cur){
        if(k<=siz[ls])  cur=ls;
        else  if(k>siz[ls]+cnt[cur]){
                k-=siz[ls]+cnt[cur];cur=rs;
        }else  return val[cur];
    }return 0;
} 
int las(int x){
    int cur=root,ans=-1;
    while(cur){
        if(x>val[cur])  ans=val[cur],cur=rs;
        else cur=ls;
    }return ans;
}
int nex(int x){
    int cur=root,ans=-1;
    while(cur){
        if(x<val[cur])  ans=val[cur],cur=ls;
        else  cur=rs;
    }return ans;
}
View Code

无旋/FHQ

inline int get(int x){
    t[++tot]={0,0,x,rand(),1};return tot;
}inline void pushup(int pos){t[pos].siz=t[t[pos].l].siz+t[t[pos].r].siz;}
void split(int pos,int x,int &l,int &r){
    if(!pos){l=r=0;return;}
    if(t[pos].key<=x){l=pos;split(t[l].r,x,t[l].r,r);}
    else{r=pos;split(t[r].l,x,l,r[r].l);}
    pushup(pos);
}int merge(int l,int r){
    if(!l||!r)  return l|r;
    if(t[l].val<=t[r].val){
        t[l].r=merge(t[l].r,r);
        pushup(l);return l;
    }t[r].l=merge(l,t[r].l);
    pushup(r);return r;
}inline void insert(int x){
    split(rt,x-1,dl,dr);rt=merge(merge(dl,get(x)),dr);
}inline void del(int x){
    split(rt,x-1,dl,dr);split(dr,x,tmp,dr);
    tmp=merge(t[tmp].l,t[tmp].r);rt=merge(merge(dl,tmp),dr);
}inline int getrk(int x){
    split(rt,x-1,dl,dr);int rk=t[dl].size+1;
    rt=merge(dl,dr);return rk;
}int getnum(int pos,int x){
    int num=t[t[pos].l].siz+1;
    if(num==x)  return t[pos].key;
    if(num>x)  return getnum(t[pos].l,x);
    return getnum(t[pos].r,x-num);
}inline int pre(int x){
    split(rt,x-1,dl,dr);
    int num=getnum(dl,t[dl].siz);
    rt=merge(dl,dr);return num;
}inline int nxt(int x){
    split(rt,x,dl,dr);
    int num=getnum(dr,1);
    rt=merge(dl,dr);return num;
}
View Code

可持久化

例题

只是在split复制了节点

#include<bits/stdc++.h>
using namespace std;
const int MAX=5e5+10;
const int inf=(1ll<<31)-1;
int n,rt[MAX],i,tot,dl,dr,tmp,v,opt,x;
struct node{
    int l,r,key,val,siz;
} t[MAX*50];
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
inline int get(int x){
    t[++tot]={0,0,x,rand(),1};return tot;
}inline void pushup(int pos){t[pos].siz=t[t[pos].l].siz+t[t[pos].r].siz+1;}
void split(int pos,int x,int &l,int &r){
    if(!pos){l=r=0;return;}
    int now=++tot;t[now]=t[pos];
    if(t[now].key<=x){l=now;split(t[l].r,x,t[l].r,r);}
    else{r=now;split(t[r].l,x,l,t[r].l);}
    pushup(now);
}int merge(int l,int r){
    if(!l||!r)  return l|r;
    if(t[l].val<=t[r].val){
        t[l].r=merge(t[l].r,r);
        pushup(l);return l;
    }t[r].l=merge(l,t[r].l);
    pushup(r);return r;
}inline void insert(int x){
    split(rt[i],x-1,dl,dr);rt[i]=merge(merge(dl,get(x)),dr);
}inline void del(int x){
    split(rt[i],x-1,dl,dr);split(dr,x,tmp,dr);
    tmp=merge(t[tmp].l,t[tmp].r);rt[i]=merge(merge(dl,tmp),dr);
}inline int getrk(int x){
    split(rt[i],x-1,dl,dr);int rk=t[dl].siz;
    rt[i]=merge(dl,dr);return rk;
}int getnum(int pos,int x){
    int num=t[t[pos].l].siz+1;
    if(num==x)  return t[pos].key;
    if(num>x)  return getnum(t[pos].l,x);
    return getnum(t[pos].r,x-num);
}inline int pre(int x){
    split(rt[i],x-1,dl,dr);
    int num=getnum(dl,t[dl].siz);
    rt[i]=merge(dl,dr);return num;
}inline int nxt(int x){
    split(rt[i],x,dl,dr);
    int num=getnum(dr,1);
    rt[i]=merge(dl,dr);return num;
}
signed main(){
    n=read();
    insert(inf);insert(-inf);
    for(i=1;i<=n;++i){
        v=read();opt=read();x=read();
        rt[i]=rt[v];
        if(opt==1)  insert(x);
        if(opt==2)  del(x);
        if(opt==3)  printf("%d\n",getrk(x));
        if(opt==4)  printf("%d\n",getnum(rt[i],x+1));
        if(opt==5)  printf("%d\n",pre(x));
        if(opt==6)  printf("%d\n",nxt(x));
    }
}
View Code

 在merge中也复制节点。在下放标记时可以省略split

#include<bits/stdc++.h>
using namespace std;
const int MAX=5e5+10;
const int inf=(1ll<<31)-1;
int n,rt[MAX],i,tot,dl,dr,tmp,v,opt,x;
struct node{
    int l,r,key,val,siz;
} t[MAX*50];
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
inline int get(int x){
    t[++tot]={0,0,x,rand(),1};return tot;
}inline void pushup(int pos){t[pos].siz=t[t[pos].l].siz+t[t[pos].r].siz+1;}
void split(int pos,int x,int &l,int &r){
    if(!pos){l=r=0;return;}
    int now=++tot;t[now]=t[pos];
    if(t[now].key<=x){l=now;split(t[l].r,x,t[l].r,r);}
    else{r=now;split(t[r].l,x,l,t[r].l);}
    pushup(now);
}int merge(int l,int r){
    if(!l||!r)  return l|r;
    int now=++tot;
    if(t[l].val<=t[r].val){
        t[now]=t[l];
        t[now].r=merge(t[now].r,r);
    }else{t[now]=t[r];t[now].l=merge(l,t[now].l);}
    pushup(now);return now;
}inline void insert(int x){
    split(rt[i],x-1,dl,dr);rt[i]=merge(merge(dl,get(x)),dr);
}inline void del(int x){
    split(rt[i],x-1,dl,dr);split(dr,x,tmp,dr);
    tmp=merge(t[tmp].l,t[tmp].r);rt[i]=merge(merge(dl,tmp),dr);
}inline int getrk(int x){
    split(rt[i],x-1,dl,dr);int rk=t[dl].siz;
    rt[i]=merge(dl,dr);return rk;
}int getnum(int pos,int x){
    int num=t[t[pos].l].siz+1;
    if(num==x)  return t[pos].key;
    if(num>x)  return getnum(t[pos].l,x);
    return getnum(t[pos].r,x-num);
}inline int pre(int x){
    split(rt[i],x-1,dl,dr);
    int num=getnum(dl,t[dl].siz);
    rt[i]=merge(dl,dr);return num;
}inline int nxt(int x){
    split(rt[i],x,dl,dr);
    int num=getnum(dr,1);
    rt[i]=merge(dl,dr);return num;
}
signed main(){
    n=read();
    insert(inf);insert(-inf);
    for(i=1;i<=n;++i){
        v=read();opt=read();x=read();
        rt[i]=rt[v];
        if(opt==1)  insert(x);
        if(opt==2)  del(x);
        if(opt==3)  printf("%d\n",getrk(x));
        if(opt==4)  printf("%d\n",getnum(rt[i],x+1));
        if(opt==5)  printf("%d\n",pre(x));
        if(opt==6)  printf("%d\n",nxt(x));
    }
}
View Code

 

posted @ 2023-01-27 07:51  yisiwunian  阅读(13)  评论(0编辑  收藏  举报