普通平衡树

普通平衡树


splay

板子、、、写的有点长

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define Fname "splay"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=100010;
int ch[maxn][2],fa[maxn],siz[maxn],val[maxn],cnt[maxn],root,tot;
il vd updata(const int&x){if(x)siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];}
il vd clear(const int&x){fa[x]=ch[x][0]=ch[x][1]=siz[x]=val[x]=cnt[x]=0;}
il vd rotate(const int&x){
    rg int y=fa[x],z=fa[y],k=x==ch[y][1];
    fa[x]=z;
    if(z)ch[z][y==ch[z][1]]=x;
    ch[y][k]=ch[x][k^1],fa[ch[y][k]]=y;
    fa[y]=x,ch[x][k^1]=y;
    updata(y),updata(x);
}
il vd splay(const int&x,const int&f=0){
    rg int y,z;
    while(fa[x]^f){
    y=fa[x],z=fa[fa[x]];
    if(z^f)
        if((x==ch[y][0])^(y==ch[z][0]))rotate(x);
        else rotate(y);
    rotate(x);
    }
    if(f==0)root=x;
}
il vd ins(const int&v){
    if(root==0){++tot,cnt[tot]=1,val[tot]=v,siz[tot]=1,root=tot;return;}
    int x=root,y=0;
    while(1){
    if(v==val[x]){++cnt[x],updata(x),updata(y),splay(x);return;}
    y=x,x=ch[x][val[x]<v];
    if(!x){
        ++tot;
        fa[tot]=y,ch[y][val[y]<v]=tot;
        siz[tot]=cnt[tot]=1,val[tot]=v;
        updata(y),splay(tot);return;
    }
    }
}
il int rk(int k){
    int x=root,ret=1;
    while(1)
    if(k<val[x])x=ch[x][0];
    else{
        ret+=siz[ch[x][0]];
        if(k==val[x]){splay(x);return ret;}
        ret+=cnt[x],x=ch[x][1];
    }
}
il int kth(int k){
    int x=root;
    while(1)
    if(k<=siz[ch[x][0]])x=ch[x][0];
    else{
        k-=cnt[x]+siz[ch[x][0]];
        if(k<=0){splay(x);return val[x];}
        x=ch[x][1];
    }
}
il int pre_next(bool k){
    int x=ch[root][k];
    while(ch[x][k^1])x=ch[x][k^1];
    return x;
}
il vd del(int x){
    rk(x);
    int old=root;
    if(cnt[root]>1){--cnt[root],updata(root);return;}
    if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}
    if(!ch[root][0]){root=ch[root][1],fa[root]=0,clear(old);return;}
    if(!ch[root][1]){root=ch[root][0],fa[root]=0,clear(old);return;}
    int k=rand()%2,pre=pre_next(k);
    splay(pre);
    ch[root][k^1]=ch[old][k^1];
    fa[ch[old][k^1]]=root;
    clear(old),updata(root);
}
int main(){
    srand(time(NULL));
    int n=gi(),opt,x;
    rep(i,1,n){
    opt=gi(),x=gi();
    if(opt==1)ins(x);
    else if(opt==2)del(x);
    else if(opt==3)printf("%d\n",rk(x));
    else if(opt==4)printf("%d\n",kth(x));
    else{
        ins(x);
        printf("%d\n",val[pre_next(opt-5)]);
        del(x);
    }
    }
    return 0;
}

旋转版treap

跑得快然而没卵用。

// It is made by XZZ
#include<cstdio>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define Ls tree[now].ls
#define Rs tree[now].rs
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct node{
    int ls,rs,value,rand,sum,size;
    node(){ls=rs=value=rand=sum=size=0;}
}tree[100001];
int root=0,siz=0;
ll seed=19260817;
il int Rand(){return seed=seed*48271LL%2147483647;}
il vd reset(int now){
    tree[now].size=tree[Ls].size+tree[Rs].size+tree[now].sum;
}
il vd lrot(int&now){
    int ls=tree[now].ls;
    tree[now].ls=tree[ls].rs,tree[ls].rs=now;
    tree[ls].size=tree[now].size;reset(now);now=ls;
}
il vd rrot(int&now){
    int rs=tree[now].rs;
    tree[now].rs=tree[rs].ls,tree[rs].ls=now;
    tree[rs].size=tree[now].size;reset(now);now=rs;
}
il vd ins(int&now,int num){
    if(now==0){
    ++siz,now=siz,tree[now].size=tree[now].sum=1,tree[now].value=num,tree[now].rand=Rand();
    return;
    }
    ++tree[now].size;
    if(tree[now].value==num)++tree[now].sum;
    else if(num<tree[now].value){
    ins(Ls,num);
    if(tree[Ls].rand<tree[now].rand)lrot(now);
    }else{
    ins(Rs,num);
    if(tree[Rs].rand<tree[now].rand)rrot(now);
    }
}
il vd del(int&now,int num){
    if(now==0)return;
    if(tree[now].value==num){
    if(tree[now].sum>1){--tree[now].sum,--tree[now].size;return;}
    if(!Ls||!Rs)now=Ls|Rs;
    else if(tree[Ls].rand<tree[Rs].rand)lrot(now),del(now,num);
    else rrot(now),del(now,num);
    return;
    }
    --tree[now].size;
    if(num<tree[now].value)del(Ls,num);
    else del(Rs,num);
}
il int getrank(int now,int num){
    if(now==0)return 0;
    if(tree[now].value==num)return tree[Ls].size+1;
    if(num>tree[now].value)return tree[Ls].size+tree[now].sum+getrank(Rs,num);
    else return getrank(Ls,num);
}
il int getnum(int now,int num){
    if(num<=tree[Ls].size)return getnum(Ls,num);
    else if(num>tree[Ls].size+tree[now].sum)return getnum(Rs,num-tree[Ls].size-tree[now].sum);
    else return tree[now].value;
}
int ans;
il vd lower(int now,int num){
    if(now==0)return;
    if(tree[now].value<num)ans=now,lower(Rs,num);
    else lower(Ls,num);
}
il vd upper(int now,int num){
    if(now==0)return;
    if(tree[now].value>num)ans=now,upper(Ls,num);
    else upper(Rs,num);
}
int main(){
    int n=gi(),opt,x;
    while(n--){
    opt=gi(),x=gi();
    switch(opt){
        case 1:ins(root,x);break;
        case 2:del(root,x);break;
            case 3:printf("%d\n",getrank(root,x));break;
        case 4:printf("%d\n",getnum(root,x));break;
        case 5:ans=0,lower(root,x),printf("%d\n",tree[ans].value);break;
        case 6:ans=0,upper(root,x),printf("%d\n",tree[ans].value);break;
    }
    }
    return 0;
}

无旋treap

是不是我常数写大了?好慢。。。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define mp make_pair
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
#define Now tree[now]
struct node{int ls,rs,value,rand,size;}tree[100010];
int root,siz;
int seed=151806+150605+151127;//mou shen ben xue hao+mou da lao xue hao+mou ju ruo xue hao
il int Rand(){return seed=seed*48271%2147483647;}
il vd reset(int now){Now.size=tree[Now.ls].size+tree[Now.rs].size+1;}
il int merge(int a,int b){
    if(!a||!b)return a|b;
    if(tree[a].rand<tree[b].rand){tree[a].rs=merge(tree[a].rs,b),reset(a);return a;}
    else {tree[b].ls=merge(a,tree[b].ls),reset(b);return b;}
}
il pair<int,int> split(int now,int num){
    if(!now)return mp(0,num);
    int ls=Now.ls,rs=Now.rs;
    if(num==tree[ls].size){Now.ls=0,reset(now);return mp(ls,now);}
    if(num==tree[ls].size+1){Now.rs=0,reset(now);return mp(now,rs);}
    if(num<tree[ls].size){
    pair<int,int>T=split(ls,num);
    Now.ls=T.second,reset(now);
    return mp(T.first,now);
    }else{
    pair<int,int>T=split(rs,num-tree[ls].size-1);
    Now.rs=T.first,reset(now);
    return mp(now,T.second);
    }
}
il int getrank(int now,int num){
    int ret=0,t=1e9;
    while(now){
    if(num==Now.value)t=min(t,ret+tree[Now.ls].size+1);
        if(num<=Now.value)now=Now.ls;
        else ret+=tree[Now.ls].size+1,now=Now.rs;
    }
    return t==1e9?ret:t;
}
il int getnum(int now,int num){
    while(1){
        if(tree[Now.ls].size==num-1)return Now.value;
        if(tree[Now.ls].size>num-1)now=Now.ls;
        else num-=tree[Now.ls].size+1,now=Now.rs;
    }
}
il int lower(int now,int num){
    int ret;
    while(now)if(tree[now].value<num)ret=tree[now].value,now=Now.rs;
        else now=Now.ls;
    return ret;
}
il int upper(int now,int num){
    int ret;
    while(now)if(tree[now].value>num)ret=tree[now].value,now=Now.ls;
        else now=Now.rs;
    return ret;
}
il vd ins(int num){
    int Rank=getrank(root,num),now;
    pair<int,int>tmp=split(root,Rank);
    now=++siz;
    Now.value=num,Now.rand=Rand(),Now.size=1;
    root=merge(tmp.first,siz);
    root=merge(root,tmp.second);
}
il vd del(int num){
    int Rank=getrank(root,num);
    pair<int,int>t1=split(root,Rank),t2=split(t1.first,Rank-1);
    root=merge(t2.first,t1.second);
}
int main(){
    int n=gi(),opt,x;
    while(n--){
    opt=gi(),x=gi();
    switch(opt){
        case 1:ins(x);break;
        case 2:del(x);break;
            case 3:printf("%d\n",getrank(root,x));break;
        case 4:printf("%d\n",getnum(root,x));break;
        case 5:printf("%d\n",lower(root,x));break;
        case 6:printf("%d\n",upper(root,x));break;
    }
    }
    return 0;
}

SGT

即替罪羊树。重构的思想很不错,常数小,因为我把alpha设成了0.7233333

// It is made by XZZ
#include<cstdio>
#include<algorithm>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=1e6+2;
const double alpha=0.7233333;
int root,id,val[maxn],ch[maxn][2],siz[maxn],cover[maxn],b[maxn];
bool del[maxn];
il int newnode(int _val){val[++id]=_val,ch[id][0]=ch[id][1]=0,siz[id]=cover[id]=1;return id;}
il vd dfs(const int&rt){
    if(!rt)return;
    dfs(ch[rt][0]);
    if(!del[rt])b[++b[0]]=rt;
    dfs(ch[rt][1]);
}
il int divide(int l,int r){
    if(l>r)return 0;
    int mid=(l+r)>>1;
    ch[b[mid]][0]=divide(l,mid-1);
    ch[b[mid]][1]=divide(mid+1,r);
    siz[b[mid]]=siz[ch[b[mid]][0]]+siz[ch[b[mid]][1]]+!del[b[mid]];
    cover[b[mid]]=cover[ch[b[mid]][0]]+cover[ch[b[mid]][1]]+1;
    return b[mid];
}
il vd rebuild(int&rt){
    b[0]=0;dfs(rt);rt=divide(1,b[0]);
}
il int*_Insert(int&rt,const int&num){
    if(!rt){rt=newnode(num);return NULL;}
    ++siz[rt],++cover[rt];
    int*ret=_Insert(ch[rt][num>=val[rt]],num);
    if(max(cover[ch[rt][0]],cover[ch[rt][1]])>alpha*cover[rt])ret=&rt;
    return ret;
}
il vd Insert(const int&x){int*ls=_Insert(root,x);if(ls)rebuild(*ls);}
il int Rank(const int&x){
    int ret=1,now=root;
    while(now)
    if(x<=val[now])now=ch[now][0];
    else ret+=siz[ch[now][0]]+!del[now],now=ch[now][1];
    return ret;
}
il int Kth(int k){
    int now=root;
    while(now){
    if(!del[now]&&k==siz[ch[now][0]]+1)return val[now];
    if(k<=siz[ch[now][0]])now=ch[now][0];
    else k-=siz[ch[now][0]]+!del[now],now=ch[now][1];
    }
}
il vd _Erase(int k){
    int now=root;
    while(now){
    --siz[now];
    if(!del[now]&&k==siz[ch[now][0]]+1){del[now]=1;return;}
    if(k<=siz[ch[now][0]])now=ch[now][0];
    else k-=siz[ch[now][0]]+!del[now],now=ch[now][1];
    }
}
il vd Erase(const int&x){
    _Erase(Rank(x));
    if(siz[root]<cover[root]*alpha)rebuild(root);
}
int main(){
    int n=gi(),opt,x;
    while(n--){
    opt=gi(),x=gi();
    if(opt==1)Insert(x);
    else if(opt==2)Erase(x);
    else if(opt==3)printf("%d\n",Rank(x));
    else if(opt==4)printf("%d\n",Kth(x));
    else if(opt==5)printf("%d\n",Kth(Rank(x)-1));
    else printf("%d\n",Kth(Rank(x+1)));
    }
    return 0;
}

vector

%烂hzwer大佬。。。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
vector<int>A;
int main(){
    int n=gi(),opt,x;
    while(n--){
    opt=gi(),x=gi();
    if(opt==1)A.insert(upper_bound(A.begin(),A.end(),x),x);
    else if(opt==2)A.erase(lower_bound(A.begin(),A.end(),x));
    else if(opt==3)printf("%d\n",lower_bound(A.begin(),A.end(),x)-A.begin()+1);
    else if(opt==4)printf("%d\n",A[x-1]);
    else if(opt==5)printf("%d\n",*--lower_bound(A.begin(),A.end(),x));
    else printf("%d\n",*upper_bound(A.begin(),A.end(),x));
    }
    return 0;
}

BIT+二分答案

用一颗区间修改单点查询的BIT存储rk就行了,剩下全用二分

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define Fname "phs"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m;
struct bit{//区间修改、单点查询的BIT,存的是有多少个数小于这个数
    int tree[100010];
    il int lb(const int&a){return a&-a;}
    bit(){memset(tree,0,sizeof tree);}
    il vd Updata(int pos,int num){while(pos<=m)tree[pos]+=num,pos+=lb(pos);}
    il int Query(int pos){int ret=0;while(pos)ret+=tree[pos],pos-=lb(pos);return ret;}
};
int opt[100010],x[100010],data[100010];
bit t;
int main(){
    n=gi();
    rep(i,1,n){
    opt[i]=gi(),x[i]=gi();
    if(opt[i]!=4)data[++m]=x[i];
    }
    sort(data+1,data+m+1);
    m=unique(data+1,data+m+1)-data-1;
    rep(i,1,n)if(opt[i]!=4)x[i]=lower_bound(data+1,data+1+m,x[i])-data;
    int l,r,mid,k;
    rep(i,1,n){
    if(opt[i]==1)t.Updata(x[i]+1,1);
    else if(opt[i]==2)t.Updata(x[i]+1,-1);
    else if(opt[i]==3)printf("%d\n",t.Query(x[i])+1);
    else if(opt[i]==4){
        l=1,r=m;
        while(l<r){
        mid=(l+r)>>1;
        if(t.Query(mid+1)>=x[i])r=mid;
        else l=mid+1;
        }
        printf("%d\n",data[l]);
    }else if(opt[i]==5){
        k=t.Query(x[i]);
        l=1,r=x[i]-1;
        while(l<r){
        mid=(l+r)>>1;
        if(t.Query(mid+1)==k)r=mid;
        else l=mid+1;
        }
        printf("%d\n",data[l]);
    }else{
        k=t.Query(x[i]+1);
        l=x[i]+1,r=m;
        while(l<r){
        mid=(l+r)>>1;
        if(t.Query(mid)==k)l=mid+1;
        else r=mid;
        }
        printf("%d\n",data[l-1]);
    }
    }
    //基本是二分答案(OwO)
    return 0;
}

还有几个没写

  • 值域线段树
  • set(加二分和氧气也是可以的吧?)
  • 还有二进制trie树?
  • 平板电视pb_ds库有自带吧

另外,置顶&坐看访问量暴涨

posted @ 2017-09-24 22:16  菜狗xzz  阅读(1193)  评论(4编辑  收藏  举报