二逼平衡树(树套树)
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
查询k在区间内的排名
查询区间内排名为k的值
修改某一位值上的数值
查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
#注意上面两条要求和tyvj或者bzoj不一样,请注意
输入格式
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
输出格式
对于操作1,2,4,5各输出一行,表示查询结果
输入输出样例
输入 #1 复制
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
输出 #1 复制
2
4
3
4
9
说明/提示
时空限制:2s,128M
n,m \leq 5\cdot {10}^4 n,m≤5⋅10
4
保证有序序列所有值在任何时刻满足 [0, {10} ^8] [0,10
8
]
题目来源:bzoj3196 / Tyvj1730 二逼平衡树,在此鸣谢
此数据为洛谷原创。(特别提醒:此数据不保证操作4、5一定存在,故请务必考虑不存在的情况)
题解:如果不存在修改操作就是静态第k大问题,可以使用普通的主席树解决,加上修改操作就变成了动态第k大问题。动态第k大如果强制在线可以使用线段树套平衡树利用二分做,也可以使用复杂度低一个log的树状数组套主席树做(还不会…待补),如果可以离线,那么可以使用更优秀的cdq分治和整体二分(还不会,待补)
关于平衡树splay写法
rotate操作:
- 更新当前结点x与其父节点f以及其儿子结点s以及父结点的父节点gf的关系
- pushup更新其原父节点f以及当前结点x的数据
splay操作:
- 如果当前结点x的父结点不是根节点并且当前结点与其父节点以及其父节点的父节点在同一条线上,简单地rotate(x)会导致树不平衡所以需要先对父节点f进行rotate(f)然后rotate(x)
- 否则直接执行rotate(x)将当前结点朝根节点方向移动
insert操作:
- 先找到要插入的位置
- 插入
- pushup更新插入结点以及父结点的数据
- 把插入结点splay到根节点
delete操作:
-
将要删除的结点splay到根节点
-
如果要删除结点x的cnt>1,那么简单地进行cnt–即可
-
如果要删除结点x的cnt<1
- 如果要删除结点x没有儿子结点,那么直接进行clear操作清除结点数据即可
- 如果含有一个儿子结点,那么将唯一的儿子作为根,然后clear清除结点x数据
- 如果含有两个儿子,那么先找到x的前驱s,将s进行splay操作到根节点,然后把x的右儿子交给s,然后clear清除x数据
-
pushup更新相关节点数据
线段树套平衡树
#include<bits/stdc++.h>
using namespace std;
//#define debug(x) cout<<#x<<" is "<<x<<endl;
typedef long long ll;
const int maxn=5e4+5;
const int inf=2147483647;
struct pot{
int f;
int siz;
int cnt;
int key;
int son[2];
pot(){f=cnt=siz=son[0]=son[1]=0;}
}p[maxn*40];
int tot;
struct Splay{
int rt;
Splay(){rt=0;}
void Clear(int id){
p[id].cnt=p[id].siz=p[id].key=p[id].f=p[id].son[0]=p[id].son[1]=0;
}
void pushup(int id){
if(id){
p[id].siz=p[id].cnt;
p[id].siz+=p[p[id].son[0]].siz;
p[id].siz+=p[p[id].son[1]].siz;
}
}
void rotat(int id){
int f1=p[id].f;
int f2=p[f1].f;
p[f1].f=id;
int s1=p[id].son[p[f1].son[0]==id];
p[id].son[p[f1].son[0]==id]=f1;
p[f1].son[p[f1].son[1]==id]=s1;
p[s1].f=f1;
p[f2].son[p[f2].son[1]==f1]=id;
p[id].f=f2;
pushup(f1);
pushup(id);
}
void splay(int sta,int en){
while(p[sta].f!=en){
if(p[p[sta].f].f!=en){
if((p[p[p[sta].f].f].son[0]==p[sta].f)^(p[p[sta].f].son[0]==sta)){
rotat(sta);
}
else{
rotat(p[sta].f);
rotat(sta);
}
}
else{
rotat(sta);
}
}
if(en==0)rt=sta;
}
void inser(int x){
if(rt==0){
rt=++tot;
p[rt].siz=p[rt].cnt=1;
p[rt].key=x;
p[rt].son[0]=p[rt].son[1]=p[rt].f=0;
return;
}
int w=rt;
while(1){
if(p[w].key==x){
p[w].cnt++;
pushup(w);
pushup(p[w].f);
splay(w,0);
return;
}
if(p[w].key>x){
if(p[w].son[0]){
w=p[w].son[0];
}
else{
p[w].son[0]=++tot;
p[tot].cnt=p[tot].siz=1;
p[tot].f=w;
p[tot].key=x;
p[tot].son[0]=p[tot].son[1]=0;
pushup(tot);
pushup(w);
splay(tot,0);
return;
}
}
if(p[w].key<x){
if(p[w].son[1]){
w=p[w].son[1];
}
else{
p[w].son[1]=++tot;
p[tot].cnt=p[tot].siz=1;
p[tot].f=w;
p[tot].key=x;
p[tot].son[0]=p[tot].son[1]=0;
pushup(tot);
pushup(w);
splay(tot,0);
return;
}
}
}
}
int rk(int x){
int ans=0;
int w=rt;
while(1){
if(w==0)break;
if(p[w].key>x){
w=p[w].son[0];
}
else{
ans+=p[p[w].son[0]].siz;
if(p[w].key==x){
splay(w,0);
return ans;
}
ans+=p[w].cnt;
w=p[w].son[1];
}
}
return ans;
}
int pre(int id,int x){
if(id==0)return -inf;
if(p[id].key>=x){
return pre(p[id].son[0],x);
}
else{
return max(p[id].key,pre(p[id].son[1],x));
}
}
int nxt(int id,int x){
if(id==0)return inf;
if(p[id].key<=x){
return nxt(p[id].son[1],x);
}
else{
return min(p[id].key,nxt(p[id].son[0],x));
}
}
void del(int x){
rk(x);
if(p[rt].cnt>1){p[rt].cnt--;pushup(rt);return;}
else if(p[rt].son[0]==0&&p[rt].son[1]==0){Clear(rt);rt=0;return;}
else if(p[rt].son[0]==0){
int oldrt=rt;
rt=p[rt].son[1];
p[rt].f=0;
Clear(oldrt);
return;
}
else if(p[rt].son[1]==0){
int oldrt=rt;
rt=p[rt].son[0];
p[rt].f=0;
Clear(oldrt);
return;
}
else{
int oldrt=rt;
int xx=pre(rt,x);
rk(xx);
p[rt].son[1]=p[oldrt].son[1];
p[p[rt].son[1]].f=rt;
Clear(oldrt);
pushup(rt);
p[rt].f=0;
return;
}
}
}a[maxn<<2];
int b[maxn];
void build(int rwt,int l,int r){
for(int i=l;i<=r;i++){
a[rwt].inser(b[i]);
}
if(l==r)return;
int mid=(l+r)>>1;
build(rwt<<1,l,mid);
build((rwt<<1)|1,mid+1,r);
}
int query1(int rwt,int l,int r,int x,int l0,int r0){
if(l>=l0&&r<=r0){return a[rwt].rk(x);}
int mid=(l+r)>>1;
int xx=0;
if(mid>=l0)xx+=query1(rwt<<1,l,mid,x,l0,r0);
if(mid<r0)xx+=query1((rwt<<1)|1,mid+1,r,x,l0,r0);
return xx;
}
void update(int rwt,int l,int r,int x,int pos,int k){
if(l<=pos&&r>=pos){
a[rwt].del(x);
a[rwt].inser(k);
}
if(l==r)return;
int mid=(l+r)>>1;
if(mid>=pos)update(rwt<<1,l,mid,x,pos,k);
else update((rwt<<1)|1,mid+1,r,x,pos,k);
}
int query2(int rwt,int l,int r,int k,int l0,int r0){
int L=0;
int R=1e8;
int ans;
while(L<=R){
int mid=(L+R)>>1;
if(query1(rwt,l,r,mid,l0,r0)+1<=k){
ans=mid;
L=mid+1;
}
else{
R=mid-1;
}
}
return ans;
}
int query3(int rwt,int l,int r,int x,int l0,int r0){
if(l>=l0&&r<=r0){
return a[rwt].pre(a[rwt].rt,x);
}
int mid=(l+r)>>1;
int xx=-inf;
if(mid>=l0)xx=max(xx,query3(rwt<<1,l,mid,x,l0,r0));
if(mid<r0)xx=max(xx,query3((rwt<<1)|1,mid+1,r,x,l0,r0));
return xx;
}
int query4(int rwt,int l,int r,int x,int l0,int r0){
if(l>=l0&&r<=r0){
return a[rwt].nxt(a[rwt].rt,x);
}
int mid=(l+r)>>1;
int xx=inf;
if(mid>=l0)xx=min(xx,query4(rwt<<1,l,mid,x,l0,r0));
if(mid<r0)xx=min(xx,query4((rwt<<1)|1,mid+1,r,x,l0,r0));
return xx;
}
int main(){
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
build(1,1,n);
while(q--){
int op,c,d,e;
scanf("%d%d%d",&op,&c,&d);
if(op==3){
update(1,1,n,b[c],c,d);
b[c]=d;
}
else{
scanf("%d",&e);
if(op==1){
printf("%d\n",query1(1,1,n,e,c,d)+1);
}
else if(op==2){
printf("%d\n",query2(1,1,n,e,c,d));
}
else if(op==4){
printf("%d\n",query3(1,1,n,e,c,d));
}
else if(op==5){
printf("%d\n",query4(1,1,n,e,c,d));
}
}
}
return 0;
}