普通平衡树
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
",rk(x));
else if(opt==4)printf("%d
",kth(x));
else{
ins(x);
printf("%d
",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
",getrank(root,x));break;
case 4:printf("%d
",getnum(root,x));break;
case 5:ans=0,lower(root,x),printf("%d
",tree[ans].value);break;
case 6:ans=0,upper(root,x),printf("%d
",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
",getrank(root,x));break;
case 4:printf("%d
",getnum(root,x));break;
case 5:printf("%d
",lower(root,x));break;
case 6:printf("%d
",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
",Rank(x));
else if(opt==4)printf("%d
",Kth(x));
else if(opt==5)printf("%d
",Kth(Rank(x)-1));
else printf("%d
",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
",lower_bound(A.begin(),A.end(),x)-A.begin()+1);
else if(opt==4)printf("%d
",A[x-1]);
else if(opt==5)printf("%d
",*--lower_bound(A.begin(),A.end(),x));
else printf("%d
",*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
",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
",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
",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
",data[l-1]);
}
}
//基本是二分答案(OwO)
return 0;
}
还有几个没写
- 值域线段树
- set(加二分和氧气也是可以的吧?)
- 还有二进制trie树?
- 平板电视pb_ds库有自带吧