题解:普通平衡树

(内容更新ing)

Treap

首先是标准的Treap,楼上的dalao们已经说的很清楚了

// treap my 数组

#include <algorithm>
#include <iostream>
#include <cstdio>
#define FOR(i,n,m) for(int i=n;i<=m;++i)
#define il inline
using namespace std;

#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
static char buf[100000],*pa(buf),*pb(buf);
#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++	//玄学快读
il int read()
{
    register int x(0);register int f(1);register char c(gc);
    while((c<'0'||c>'9')&&c!='-')c=gc;
    c=='-'?f=-1,c=gc:f;
    while(c>='0'&&c<='9')x=x*10+(c^48),c=gc;
    return f*x;
}

const int N=100100,INF=(1<<29);
struct Treap {
    int lc,rc,key,pri,size,cnt;
}a[N];
#define c(x) a[x].cnt
#define s(x) a[x].size
#define p(x) a[x].pri
#define v(x) a[x].key
#define rc(x) a[x].rc
#define lc(x) a[x].lc
#define up(k) s(k)=s(rc(k))+s(lc(k))+c(k);
//懒人的宏定义方便书写

int tot,rt;

il void zig(int &k) {	//左旋 
    int y=lc(k);
    lc(k)=rc(y);
    rc(y)=k;
    s(y)=s(k);
    up(k)
    k=y;
}

il void zag(int &k) {	//右旋 
    int y=rc(k);
    rc(k)=lc(y);
    lc(y)=k;
    s(y)=s(k);
    up(k)
    k=y;
}

il void insert(int &k,const int &key) {	//	插入 
    if(!k) {
        k=++tot;
        v(k)=key;
        p(k)=rand();
        c(k)=s(k)=1;
        lc(k)=rc(k)=0;
        return; 
    }
    else ++s(k);
    if(v(k)==key) ++c(k);
    else if(key<v(k)) {
        insert(lc(k),key);	//向左搜 
        if(p(lc(k))<p(k)) zig(k);	//左儿子优先级小,左旋 
    }
    else {
        insert(rc(k),key);
        if(p(rc(k))<p(k)) zag(k);
    }
    return;
}

il void del(int &k,const int &key) {	//删除元素 
    if(v(k)==key) {
        if(c(k)>1) --c(k),--s(k);
        else if(!lc(k) || !rc(k)) k=lc(k)+rc(k);
        else if(p(lc(k))<p(rc(k))) zig(k),del(k,key);
        else zag(k),del(k,key);
        return;
    }
    --s(k);
    if(key<v(k)) del(lc(k),key);
    else del(rc(k),key);
    return;
}

il int querypre(int key) {	//前驱 
    int x=rt,res=-INF;
    while(x) {
        if(v(x)<key) res=v(x),x=rc(x);
        else x=lc(x);
    }
    return res;
}

il int querysuf(int key) {	//后继 
    int x=rt,res=INF;
    while(x) {
        if(v(x)>key) res=v(x),x=lc(x);
        else x=rc(x);
    }
    return res;
}

il int querykth(int k) { //查找第k大元素 
    int x=rt;
    while(x) {
        if(s(lc(x))<k&&s(lc(x))+c(x)>=k) return v(x);
        if(s(lc(x))>=k) x=lc(x);
        else k-=s(lc(x))+c(x),x=rc(x);
    }
    return 0;
}

il int querdrank(int key) {	//查找元素排名 
    int x=rt,res=0;
    while(x) {
        if(key==v(x)) return res+s(lc(x))+1;
        if(key<v(x)) x=lc(x);
        else res+=s(lc(x))+c(x),x=rc(x);
    }
    return res;
}

void print(int x)
{
    if(!x) return;
    print(lc(x));
    cout<<x<<" "<<s(x)<<endl;
    print(rc(x));
}

void work() {
    int n=read();

    FOR(i,1,n) {
        int a=read(),x=read();
        if(a==1) insert(rt,x);
        if(a==2) del(rt,x);
        if(a==3) cout<<querdrank(x)<<endl;
        if(a==4) cout<<querykth(x)<<endl;
        if(a==5) cout<<querypre(x)<<endl;
        if(a==6) cout<<querysuf(x)<<endl;
    }
    return;
}

int main() {
    
    
    work();
    
    return 0;
}

整个的代码实现难度不大,主要要注意前驱,后继之类的等号问题。。(因为这个wa了很久

表示题解里面指针写的特别少。。。然后作为一个刚开始学指针的表示很无奈。。

下一段代码送给指针党

//Treap my 指针 

#include <algorithm>
#include <iostream>
#include <cstdio>
#define FOR(i,n,m) for(int i=n;i<=m;++i)
#define FR(i,n,m) for(int i=n;i>=m;--i)
#define re register
#define gc getchar()
using namespace std;
const int N=100010,INF=(1<<29);
inline int read() {
    re int x(0),f(1);
    re char ch=gc;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=gc;
    }
    while(ch>='0'&&ch<='9') {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=gc;
    }
    return x*f;
}

struct node {
    node* ch[2];	//写成这个样子之后旋转就不用写两个了
    int pri,val,size,cnt;
    node() {
        ch[0]=ch[1]=NULL;
        pri=rand();
        val=size=cnt=1;
    } 
    void update() {
        size=(ch[0]==NULL?0:ch[0]->size)+(ch[1]==NULL?0:ch[1]->size)+cnt;
    }
};
node* root;

struct treap {
        
    inline void rotate (node* &k,int d) {	//1右,0左 
        node* y=k->ch[d^1];
        k->ch[d^1]=y->ch[d];
        y->ch[d]=k;
        y->size=k->size;
        k->update();
        k=y;
    }
    
    inline void insert(node* &k,const int &key) {
        if(k==NULL) {
            k=new node;
            k->val=key;
            return;
        }
        ++k->size;
        if(k->val==key) {++k->cnt;return;}
        int a=key>k->val;
        insert(k->ch[a],key);
        if(k->ch[a]->pri>k->pri) rotate(k,a^1);
    }
    
    inline void del(node* &k,const int &key) {
        if(k==NULL) return;
        if(k->val==key) {
            if(k->cnt>1) --k->cnt,--k->size;
            else if(k->ch[0]==NULL&&k->ch[1]==NULL) k=NULL;
            else if(k->ch[0]==NULL) k=k->ch[1];
            else if(k->ch[1]==NULL) k=k->ch[0];
            else rotate(k,(int)(k->ch[0]->pri>k->ch[1]->pri)),del(k,key);
            return; 
        }
        --k->size;
        del(k->ch[key>k->val],key);
    }
    
    inline int queryrank(const int &key) {
        node* k=root;
        int ans(0);
        while(k!=NULL) {
            if(k->val==key) return ans+(k->ch[0]?k->ch[0]->size:0)+1;
            if(k->val>key) k=k->ch[0];
            else ans+=(k->ch[0]?k->ch[0]->size:0)+k->cnt,k=k->ch[1];
        }
        return ans;
    }
    
    inline int querykth(int rank) {
        node* k=root;
        while(k!=NULL) {
            int res=k->ch[0]?k->ch[0]->size:0;
            if(res<rank&&res+k->cnt>=rank) return k->val;
            if(res>=rank) k=k->ch[0];
            else rank-=res+k->cnt,k=k->ch[1];
        }
        return 0;
    }
    
    inline int querypre(const int &key) {
        node* k=root;
        int ans=-INF;
        while(k) {
            if(k->val>=key) k=k->ch[0];
            else ans=k->val,k=k->ch[1];
        }
        return ans==-INF?-1:ans;
    }
    
    inline int querysuf(const int &key) {
        node* k=root;
        int ans=INF;
        while(k) {
            if(k->val<=key) k=k->ch[1];
            else ans=k->val,k=k->ch[0];
        }
        return ans==INF?-1:ans;
    } 

}Treap;


void work() {
    int n=read();
    
    while(n--) {
        int op=read(),x=read();
        int ans;
        switch(op) {
            case 1:Treap.insert(root,x);break;
            case 2:Treap.del(root,x);break;
            case 3:cout<<Treap.queryrank(x)<<endl;break;
            case 4:cout<<Treap.querykth(x)<<endl;break;
            case 5:cout<<Treap.querypre(x)<<endl;break;
            case 6:cout<<Treap.querysuf(x)<<endl;break;
        }
    }
}

int main() {
    
//	freopen("y.txt","r",stdin);
//	freopen(".out","w",stdout);
    
    work();
    
    return 0;
}

树状数组

其实这道题目还可以用树状数组水过去。。。然后树状数组常数小,所以跑的非常非常非常地快(一百多是跑的比较快地了吧)

最重要的是 码量非常小

//树状数组

#include<cstdio>
#include <iostream>
using namespace std;
const int M=10000001;
int f[20000002],n,vmax=20000001;
#define lowbit(x) (x&(-x))
inline void add(int x,int k){
     
    while(x<=vmax) {
    	f[x]+=k;
    	x+=lowbit(x);
    }
} 

inline int getRank(int x){
    int sum(0);x;
    while(x) {
        sum+=f[x];
        x-=lowbit(x);
    } 
    return sum;
}

int find(int k){
    int ans=0,cnt=0;
    for(int i=25;i>=0;i--){
        ans+=(1<<i);
        if(ans>vmax||cnt+f[ans]>=k)
            ans-=(1<<i);
        else
            cnt+=f[ans];
    }
    return ++ans;
}
int tp;

int main(){
//	freopen("y.txt","r",stdin);
//	freopen("o.txt","w",stdout);
    n=read(); 
    int opt,x;
    while(n--){
        opt=read(),x=read();
        x+=M;
        switch(opt) {
        case 1:add(x,1);break;
        case 2:add(x,-1);break;
        case 3:write(getRank(x-1)+1);break;
        case 4:x-=M;write(find(x)-M);break;
        case 5:write(find(getRank(x-1))-M);break;
        case 6:write(find(getRank(x)+1)-M);break;
    }}
}

(我爱树状数组)

SBT树

像SBT树这种跑的快的树是很棒的

先皮一个指针:

#include <cstdio>
#include <iostream>
using namespace std;

inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return b<a?a:b;}
const int INF=(1<<29),N=100010;

int tot;
struct node {
    int val,size;
    node* ch[2]; 
    node() {
        ch[0]=ch[1]=NULL;
        size=1;
    }
    void pushup() {
        size=(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0)+1;
    }
};
node* root=NULL;

inline void rotate (node* &k,int d) {
    node* y=k->ch[d^1];
    k->ch[d^1]=y->ch[d];
    y->ch[d]=k;
    y->size=k->size;
    k->pushup();
    k=y;
}

inline void maintain(node* &x,int way) {
    if(way) {
        if(x->ch[1]==NULL) return;
        node* y=x->ch[1];
        if((y->ch[1]?y->ch[1]->size:0)>(x->ch[0]?x->ch[0]->size:0)) 
            rotate(x,0);
        else if((y->ch[0]?y->ch[0]->size:0)>(x->ch[0]?x->ch[0]->size:0)) 
            rotate(x->ch[1],1),rotate(x,0);
        else return;
    }
    else {
        if(x->ch[0]==NULL) return;
        node* y=x->ch[0];
        if((y->ch[0]?y->ch[0]->size:0)>(x->ch[1]?x->ch[1]->size:0)) 
            rotate(x,1);
        else if((y->ch[1]?y->ch[1]->size:0)>(x->ch[1]?x->ch[1]->size:0)) 	
            rotate(x->ch[0],0),rotate(x,1);
        else return;
    }
    if(x->ch[0]!=NULL) maintain(x->ch[0],0);
    if(x->ch[1]!=NULL) maintain(x->ch[1],1);
    if(x!=NULL) maintain(x,1),maintain(x,0);
}

inline void insert(node* &now,int val) {
    if(now==NULL) {
        now=new node; 
        now->val=val;
        return;
    }
    ++now->size;
    insert(now->ch[val>now->val],val);
    maintain(now,now->val<=val);
}

inline void del(node* &now,int val) {
    if(now==NULL) return;
    --now->size;
    if(now->val==val) {
        if(now->ch[0]==NULL&&now->ch[1]==NULL) now=NULL;
        else if(now->ch[0]==NULL) now=now->ch[1];
        else if(now->ch[1]==NULL) now=now->ch[0];
        else {
            node* y=now->ch[1];
            while(y->ch[0]!=NULL) y=y->ch[0];
            now->val=y->val;
            del(now->ch[1],y->val);
        }
    }
    else del(now->ch[now->val<val],val);
}

inline int rank(node* now,int val) {
    if(now==NULL) return 1;
    if(now->val<val) return rank(now->ch[1],val)+(now->ch[0]?now->ch[0]->size:0)+1;
    return rank(now->ch[0],val);
}

inline int kth(node* now,int k) {
    if(now==NULL) return 0;
    int res=(now->ch[0]?now->ch[0]->size:0);
    if(res+1==k) return now->val;
    if(res<k) return kth(now->ch[1],k-(now->ch[0]?now->ch[0]->size:0)-1);
    return kth(now->ch[0],k);
}

inline int querypre(node* now,int val) {
    if(now==NULL) 
        return ~INF+1;
    if(now->val>=val) 
        return querypre(now->ch[0],val);
    return max(now->val,querypre(now->ch[1],val));
}

inline int querysuf(node* now,int val) {
    if(now==NULL) return INF;
    if(now->val<=val) return querysuf(now->ch[1],val);
    return min(now->val,querysuf(now->ch[0],val));
}

int main() {
    
//	freopen("y.txt","r",stdin);
//	freopen("1.out","w",stdout);
    
    int n,opt,x;
    scanf("%d",&n);
    while(n--) {
        scanf("%d%d",&opt,&x);
        switch(opt) {
            case 1:
                insert(root,x);break;
            case 2:
                del(root,x);break;
            case 3:
                printf("%d\n",rank(root,x));break;
            case 4:
                printf("%d\n",kth(root,x));break;
            case 5:
                printf("%d\n",querypre(root,x));break;
            case 6:
                printf("%d\n",querysuf(root,x));
        }
    }
    return 0;
}

下面是大家都看的比较爽的数组:

#include<cstdio>

#define INF 987654321
#define N 100010
inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}

int root,tot,lc[N],rc[N],val[N],siz[N];
inline void update(int now){siz[now]=siz[lc[now]]+siz[rc[now]]+1;}
inline void lr(int& x){int y=rc[x];rc[x]=lc[y],lc[y]=x,siz[y]=siz[x],update(x),x=y;}
inline void rr(int& x){int y=lc[x];lc[x]=rc[y],rc[y]=x,siz[y]=siz[x],update(x),x=y;}
inline void maintain(int& now,int way)
{
    if(way)
    {
        if(siz[rc[rc[now]]]>siz[lc[now]])lr(now);
        else if(siz[lc[rc[now]]]>siz[lc[now]])rr(rc[now]),lr(now);
        else return;
    }
    else
    {
        if(siz[lc[lc[now]]]>siz[rc[now]])rr(now);
        else if(siz[rc[lc[now]]]>siz[rc[now]])lr(lc[now]),rr(now);
        else return;
    }
    maintain(lc[now],0);
    maintain(rc[now],1);
    maintain(now,1);
    maintain(now,0);
}
inline void insert(int& now,int v)
{
    if(!now){now=++tot,val[now]=v,siz[now]=1;return;}
    ++siz[now];
    if(val[now]>v)insert(lc[now],v);
    else insert(rc[now],v);
    maintain(now,val[now]<=v);
}
inline void del(int& now,int v)
{
    if(!now)return;
    --siz[now];
    if(val[now]==v)
    {
        if(!lc[now]||!rc[now])now=lc[now]+rc[now];
        else
        {
            int tp=rc[now];
            while(lc[tp])tp=lc[tp];
            val[now]=val[tp];
            del(rc[now],val[tp]);
        }
    }
    else if(val[now]>v)del(lc[now],v);
    else del(rc[now],v);
}
inline int rank(int now,int v)
{
    if(!now)return 1;
    else if(val[now]<v)return rank(rc[now],v)+siz[lc[now]]+1;
    else return rank(lc[now],v);
}
inline int kth(int now,int v)
{
    if(!now)return -1;
    if(siz[lc[now]]+1==v)return val[now];
    else if(v<=siz[lc[now]])return kth(lc[now],v);
    else return kth(rc[now],v-siz[lc[now]]-1);
}
inline int pred(int now,int v)
{
    if(!now)return -INF;
    if(val[now]<v)return max(val[now],pred(rc[now],v));
    else return pred(lc[now],v);
}
inline int succ(int now,int v)
{
    if(!now)return INF;
    if(val[now]>v)return min(val[now],succ(lc[now],v));
    else return succ(rc[now],v);
}


int n,opt,x;

int main()
{
    n=read();
    while(n--)
    {
        opt=read(),x=read();
        switch(opt)
        {
            case 1:insert(root,x);break;
            case 2:del(root,x);break;
            case 3:write(rank(root,x));break;
            case 4:write(kth(root,x));break;
            case 5:write(pred(root,x));break;
            case 6:write(succ(root,x));
        }
    }
    return 0;
}

fhq_treap

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm> 
#include<cmath> 
#include<ctime> 
using namespace std; 
const int N=100010; 
struct trnode { 
    int son[2],v,rnd,size; 
}tr[N]; 
int tot=0,root=0; 
void update(int x) { 
    tr[x].size=tr[tr[x].son[0]].size+tr[tr[x].son[1]].size+1; 
}
int new_code(int v) {
    tot++; 
    tr[tot].size=1; 
    tr[tot].v=v; 
    tr[tot].rnd=rand();
    return tot; 
}
int merge(int x,int y) { 
    if(!x || !y) return x+y;
    if(tr[x].rnd<tr[y].rnd) { 
        tr[x].son[1]=merge(tr[x].son[1],y);
        update(x); 
        return x; 
    }
    else { 
        tr[y].son[0]=merge(x,tr[y].son[0]); 
        update(y); 
        return y; 
    } 
}
void split(int now,int k,int &x,int &y) { 
    if(!now) x=y=0; 
    else { 
        if(tr[now].v<=k) 
            x=now,split(tr[now].son[1],k,tr[now].son[1],y);
        else 
            y=now,split(tr[now].son[0],k,x,tr[now].son[0]); 
        update(now); 
    } 
}
int kth(int now,int k) {
    while(1) {
        if(k<=tr[tr[now].son[0]].size)
            now=tr[now].son[0];
        else {
            if(k==tr[tr[now].son[0]].size+1) return now;
            else {
                k-=tr[tr[now].son[0]].size+1;
                now=tr[now].son[1]; 
            }
        }
    }
}
int main() {
//	freopen("3.in","r",stdin);
    srand((unsigned)time(NULL));
    int T;
    int flag,x,y,z,a,b;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&flag,&a); 
        if(flag==1) {
            split(root,a,x,y); 
            root=merge(merge(x,new_code(a)),y);
        }
        else if(flag==2) {
            split(root,a,x,z);
            split(x,a-1,x,y);
            y=merge(tr[y].son[0],tr[y].son[1]);
            root=merge(merge(x,y),z);
        }
        else if(flag==3) {
            split(root,a-1,x,y);
            printf("%d\n",tr[x].size+1);
            root=merge(x,y);
        }
        else if(flag==4) 
            printf("%d\n",tr[kth(root,a)].v); 
        else if(flag==5) {
            split(root,a-1,x,y);
            printf("%d\n",tr[kth(x,tr[x].size)].v);
            root=merge(x,y);
        }
        else if(flag==6) {
            split(root,a,x,y);
            printf("%d\n",tr[kth(y,1)].v);
            root=merge(x,y);
        }
    }
    return 0; 
}

Splay

(不要管为什么我闲的发疯打指针)

#include <algorithm>
#include <iostream>
#include <cstdio>
#define FOR(i,n,m) for(int i=n;i<=m;++i)
#define FR(i,n,m) for(int i=n;i>=m;--i)
#define re register
#define gc getchar()
using namespace std;
const int N=100010,INF=(1<<29);

inline int read() {
    re int x(0),f(1);
    re char ch=gc;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=gc;
    }
    while(ch>='0'&&ch<='9') {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=gc;
    }
    return x*f;
}

struct node {
    int val,size,cnt;
    node* fa,*ch[2];
    node(const int &x,node* father):val(x),size(1),cnt(1),fa(father) 
    {ch[0]=ch[1]=NULL;}
    inline void pushup() {
        size=(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0)+cnt;
    }
    inline int find() {
        return fa->ch[1]==this;
    }
    inline int path(const int &new_date) {return new_date>=val;}
} * root;

inline void rotate(node* x) {
    node* y(x->fa);
    node* z(y->fa);
    int k(x->find());
    y->ch[k]=x->ch[k^1];
    if(x->ch[k^1]!=NULL) x->ch[k^1]->fa=y;
    z==NULL?root=x:z->ch[y->find()]=x;
    x->ch[k^1]=y;
    y->fa=x;
    x->fa=z;
    y->pushup(),x->pushup();
}

inline void Splay(node* x,node* goal) {
    while(x->fa!=goal) {
        node* y(x->fa);
        node* z(y->fa);
        if(z==goal) rotate(x);
        else {
            if(x->find()^(y->find()))  rotate(x),rotate(x);
            else rotate(y),rotate(x);
        }
    }
}

inline void insert(const int &val) {
    if(root==NULL) {
        root=new node(val,NULL);
        return;
    }
    for(node* t=root;t!=NULL;t=t->ch[t->path(val)]) {
        if(t->val==val) {++t->cnt,Splay(t,NULL);return;}
        if(t->ch[t->path(val)]==NULL) {
            t->ch[t->path(val)]=new node(val,t);
            Splay(t->ch[t->path(val)],NULL);
            return;
        }
    }
}

inline void del(const int &val) {
    node* t(root);
    while(t!=NULL) {
        if(t->val==val) break;
        t=t->ch[t->path(val)];
    }
    if(t==NULL) return;
    Splay(t,NULL);
    if(t->cnt>1) {--t->cnt;return;}
    if(t==NULL) return;
    if(t->ch[0]==NULL) {
        root=t->ch[1];
        if(root!=NULL) root->fa=NULL;
    }
    else {
        node* p(t->ch[0]);
        while(p->ch[1]!=NULL) p=p->ch[1];
        Splay(p,t),root=p;
        root->fa=NULL;
        p->ch[1]=t->ch[1];
        if(p->ch[1]!=NULL) p->ch[1]->fa=p;
    }
}

inline void find(const int &val) {
    node* t(root);
    while(t!=NULL&&t->val!=val) t=t->ch[t->path(val)];
    if(t!=NULL) Splay(t,NULL); 
}

inline int kth(int k) {
    node* t(root);
    while(t!=NULL) {
        int res(t->ch[0]?t->ch[0]->size:0);
        if(res<k&&res+t->cnt>=k) return t->val;
        else if(k<=res) t=t->ch[0];
        else k-=res+t->cnt,t=t->ch[1];
    }
}

inline int lower(const int &val) {
    node* t(root);
    int res;
    while(t!=NULL) {
        if(t->val<val) res=t->val,t=t->ch[1];
        else t=t->ch[0];
    }
    return res;
}

inline int upper(const int &val) {
    node* t(root);
    int res;
    while(t!=NULL) {
        if(t->val>val) res=t->val,t=t->ch[0];
        else t=t->ch[1];
    }
    return res;
}

int main() {

//	freopen("y.in","r",stdin);

    int T=read();
    while(T--) {
        switch(read()) {
            case(1):insert(read());break;
            case(2):del(read());break;
            case(3):find(read()),printf("%d\n",(root->ch[0]?root->ch[0]->size:0)+1);break;
            case(4):printf("%d\n",kth(read()));break;
            case(5):printf("%d\n",lower(read()));break;
            case(6):printf("%d\n",upper(read()));break;
        }
    }
    return 0;
}

(持续更新ing)

猜你喜欢

转载自blog.csdn.net/weixin_43464026/article/details/87368546