luogu P3369 【模板】普通平衡树

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

插入 \(x\)
删除 \(x\) 数(若有多个相同的数,因只删除一个)
查询 \(x\) 数的排名(排名定义为比当前数小的数的个数 \(+1\) )
查询排名为 \(x\) 的数
\(x\) 的前驱(前驱定义为小于 \(x\),且最大的数)
\(x\) 的后继(后继定义为大于 \(x\),且最小的数)

输入格式

第一行为 \(n\),表示操作的个数,下面 \(n\) 行每行有两个数 \(\text{opt}\)\(x\)\(\text{opt}\) 表示操作的序号( \(1 \leq \text{opt} \leq 6\) )

输出格式

对于操作 \(3,4,5,6\) 每行输出一个数,表示对应答案


Splay

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5,INF=1<<30;
inline int read(){
	int x=0,f=1; char c=getchar();
	while(c<'0'||c>'9'){ if(c=='-')f=-1;  c=getchar(); }
	while('0'<=c&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar();  }
	return x*f;	
}
int ch[N][2],par[N],val[N],cnt[N],size[N],ncnt,root;
inline bool chk(int x){ return ch[par[x]][1]==x; }
inline void pushup(int x){ size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x]; }
inline void rotate(int x){
	int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
	ch[z][chk(y)]=x,par[x]=z;
	ch[y][k]=w,par[w]=y;
	ch[x][k^1]=y,par[y]=x;
	pushup(y),pushup(x);
}
inline void splay(int x,int goal=0){
	while(par[x]!=goal){
		int y=par[x],z=par[y];
		if(z!=goal)chk(x)==chk(y)?rotate(y):rotate(x);	
		rotate(x);
	}
	if(!goal)root=x;
}
inline void insert(int x){
	int p=root,cur=0;
	while(p&&val[p]!=x)cur=p,p=ch[p][x>val[p]];
	if(p)cnt[p]++;
	else {
		p=++ncnt;
		if(cur)ch[cur][x>val[cur]]=p;
		ch[p][0]=ch[p][1]=0;
		par[p]=cur,val[p]=x;
		cnt[p]=size[p]=1;
	}
	splay(p);
}
inline void find(int x){
	int p=root;
	while(ch[p][x>val[p]]&&x!=val[p])p=ch[p][x>val[p]];
	splay(p);
}
inline int kth(int k){
	int p=root;
	while(1){
		if(ch[p][0]&&k<=size[ch[p][0]])p=ch[p][0];
		else if(k>size[ch[p][0]]+cnt[p]){
			k-=size[ch[p][0]]+cnt[p];
			p=ch[p][1];
		}else return p;
	}
}
inline int pre(int x){
	find(x);
	if(val[root]<x)return root;
	int p=ch[root][0];
	while(ch[p][1])p=ch[p][1];
	return p;	
}
inline int succ(int x){
    find(x);
    if(val[root]>x)return root;
    int p=ch[root][1];
    while(ch[p][0])p=ch[p][0];
    return p;
}
inline void remove(int x){
	int last=pre(x),nxt=succ(x);
	splay(last),splay(nxt,last);
	int p=ch[nxt][0];
	if(cnt[p]>1)cnt[p]--,splay(p);
	else ch[nxt][0]=0;	
}
int n,op,x;
signed main(){
	n=read();
	insert(INF);
	insert(-INF);
	while(n--){
		op=read(),x=read();
		switch (op){
			case 1: insert(x); break;
			case 2: remove(x); break;
			case 3: find(x); printf("%d\n",size[ch[root][0]]); break;
			case 4: printf("%d\n",val[kth(x+1)]); break;
			case 5: printf("%d\n",val[pre(x)]); break;
			case 6: printf("%d\n",val[succ(x)]); break;
		}
	}
}

Treap

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int SIZE=2e5+10;
struct Treap{
    int l,r;
    int val,dat;
    int cnt,size;
}a[SIZE];
int tot,root,n,INF=0x7fffffff;
inline int New(int val){
    a[++tot].val=val;
    a[tot].dat=rand();
    a[tot].cnt=a[tot].size=1;
    return tot;
}
inline void Update(int p){
    a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
}
inline void Build(){
    New(-INF),New(INF);
    root=1,a[1].r=2;
    Update(root);
}
int GetRankByVal(int p,int val){
    if(p==0)return 0;
    if(val==a[p].val)return a[a[p].l].size+1;
    if(val<a[p].val)return GetRankByVal(a[p].l,val);
    return GetRankByVal(a[p].r,val)+a[a[p].l].size+a[p].cnt;
}
int GetValByRank(int p,int rank){
    if(p==0)return INF;
    if(a[a[p].l].size>=rank)return GetValByRank(a[p].l,rank);
    if(a[a[p].l].size+a[p].cnt>=rank)return a[p].val;
    return GetValByRank(a[p].r,rank-a[a[p].l].size-a[p].cnt);
}
inline void zig(int &p){
    int q=a[p].l;
    a[p].l=a[q].r,a[q].r=p,p=q;
    Update(a[p].r),Update(p);
}
inline void zag(int &p){
    int q=a[p].r;
    a[p].r=a[q].l,a[q].l=p,p=q;
    Update(a[p].l),Update(p);
}
inline void Insert(int &p,int val){
    if(p==0){
        p=New(val);
        return;
    }
    if(val==a[p].val){
        a[p].cnt++,Update(p);
        return;
    }
    if(val<a[p].val){
        Insert(a[p].l,val);
        if(a[p].dat<a[a[p].l].dat)zig(p);
    }else{
        Insert(a[p].r,val);
        if(a[p].dat<a[a[p].r].dat)zag(p);
    }
    Update(p);
}
inline int GetPre(int val){
    int ans=1,p=root;
    while(p){
        if(val==a[p].val){
            if(a[p].l){
                p=a[p].l;
                while(a[p].r)p=a[p].r;
                ans=p;
            }
            break;
        }
        if(a[p].val<val&&a[p].val>a[ans].val)ans=p;
        p=val<a[p].val?a[p].l:a[p].r;
    }
    return a[ans].val;
}
inline int GetNext(int val){
    int ans=2,p=root;
    while(p){
        if(val==a[p].val){
            if(a[p].r){
                p=a[p].r;
                while(a[p].l)p=a[p].l;
                ans=p;
            }
            break;
        }
        if(a[p].val>val&&a[p].val<a[ans].val)ans=p;
        p=val<a[p].val?a[p].l:a[p].r;
    }
    return a[ans].val;
}
void Remove(int &p,int val){
    if(p==0)return;
    if(val==a[p].val){
        if(a[p].cnt>1){
            a[p].cnt--,Update(p);
            return;
        }
        if(a[p].l||a[p].r){
            if(a[p].r==0||a[a[p].l].dat>a[a[p].r].dat)zig(p),Remove(a[p].r,val);
            else zag(p),Remove(a[p].l,val);
            Update(p);
        }
        else p=0;
        return;
    }
    val<a[p].val?Remove(a[p].l,val):Remove(a[p].r,val);
    Update(p);
}
signed main(){
    srand(time(0));
    Build();
    cin>>n;
    while(n--){
        int opt,x;
        scanf("%lld%lld",&opt,&x);
        switch(opt){
            case 1:
                Insert(root,x);
                break;
            case 2:
                Remove(root,x);
                break;
            case 3:
                printf("%lld\n",GetRankByVal(root,x)-1);
                break;
            case 4:
                printf("%lld\n",GetValByRank(root,x+1));
                break;
            case 5:
                printf("%lld\n",GetPre(x));
                break;
            case 6:
                printf("%lld\n",GetNext(x));
                break;
        }
    }
    
}
posted @ 2020-01-02 19:05  白木偶君  阅读(253)  评论(0编辑  收藏  举报