您的位置:首页 > 其它

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

2017-01-14 22:59 337 查看

Description

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

1.查询k在区间内的排名

2.查询区间内排名为k的值

3.修改某一位值上的数值

4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)

5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 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的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

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


Sample Output

2
4
3
4
9


HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数

Solution

#include <stdio.h>
#include <stdlib.h>
#define N 50010
#define inf 0x7fffffff
#define opp 0x80000000
#define mid ((x>>1)+(y>>1)+(x&y&1))
#define dmax(x,y) ((x)>(y)?(x):(y))
#define dmin(x,y) ((x)<(y)?(x):(y))
#define RG register
#define inline __inline__ __attribute__((always_inline))

inline int Rin(){
RG int x=0,c=getchar(),f=1;
for(;c<48||c>57;c=getchar())
if(!(c^45))f=-1;
for(;c>47&&c<58;c=getchar())
x=(x<<1)+(x<<3)+c-48;
return x*f;
}

int n,m,a
;

namespace Seg{
struct Treap{
struct Nt{
Nt*ch[2];
int s,w,v,r;

Nt(RG int v,RG Nt*_) : v(v),r(rand()) {
s=w=1;
ch[0]=ch[1]=_;
}

inline void maintain(){
s=w+ch[0]->s+ch[1]->s;
}
}*root,*null;

Treap(){
null=new Nt(0,0x0);
null->s=null->w=0;
null->r=inf;
null->ch[0]=null->ch[1]=null;
root=null;
}

void rotate(RG Nt*&o,RG int d){
Nt*k=o->ch[1^d];
o->ch[1^d]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}

void insert(RG Nt*&o,RG int v){
if(o==null){
o=new Nt(v,null);
return;
}
o->s++;
if(v==o->v)
o->w++;
else{
RG int d=v > o->v;
insert(o->ch[d],v);
if(o->ch[d]->r < o->r)
rotate(o,1^d);
}
}

void remove(RG Nt*&o,RG int v){
if(o==null)
return;
if(o->v==v){
if(o->w>1){
o->s--;
o->w--;
return;
}
if(o->ch[0]!=null && o->ch[1]!=null){
RG int d=o->ch[0]->r > o->ch[1]->r;
rotate(o,d);
remove(o->ch[d],v);
}
else o=o->ch[o->ch[0]==null];
}
else{
o->s--;
remove(o->ch[o->v < v],v);
}
if(o!=null)
o->maintain();
}

inline int pre(RG int v){
RG int ans=opp;
for(RG Nt*o=root;o!=null;)
v > o->v ? (ans=dmax(ans,o->v),o=o->ch[1]) : o=o->ch[0];
return ans;
}

inline int nxt(RG int v){
RG int ans=inf;
for(RG Nt*o=root;o!=null;)
v < o->v ? (ans=dmin(ans,o->v),o=o->ch[0]) : o=o->ch[1];
return ans;
}

inline int rank(RG int v){
RG int ans=0;
for(Nt*o=root;o!=null;){
RG int d= v==o->v? -1 : (o->v < v);
if(d==-1){
ans+=o->ch[0]->s;
break;
}
d?(ans+=o->ch[0]->s+o->w,o=o->ch[1]):o=o->ch[0];
}
return ans;
}
}rt[N<<2];

void build(RG int x,RG int y,RG int k){
for(RG int i=x;i<=y;i++)
rt[k].insert(rt[k].root,a[i]);
if(x<y){
build(x,mid,k<<1);
build(mid+1,y,k<<1|1);
}
}

void modify(RG int x,RG int y,RG int k,RG int pos,RG int num){
rt[k].remove(rt[k].root,a[pos]);
rt[k].insert(rt[k].root,num);
if(x<y)
pos<=mid ? modify(x,mid,k<<1,pos,num):
modify(mid+1,y,k<<1|1,pos,num);
}

int getrank(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){
if(x==l && y==r)
return rt[k].rank(num);
if(r<=mid)
return getrank(x,mid,k<<1,l,r,num);
if(l>mid)
return getrank(mid+1,y,k<<1|1,l,r,num);
return getrank(x,mid,k<<1,l,mid,num)+getrank(mid+1,y,k<<1|1,mid+1,r,num);
}

int getpre(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){
if(x==l && y==r)
return rt[k].pre(num);
if(r<=mid)
return getpre(x,mid,k<<1,l,r,num);
if(l>mid)
return getpre(mid+1,y,k<<1|1,l,r,num);
return dmax(getpre(x,mid,k<<1,l,mid,num),getpre(mid+1,y,k<<1|1,mid+1,r,num));
}

int getnxt(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){
if(x==l && y==r)
return rt[k].nxt(num);
if(r<=mid)
return getnxt(x,mid,k<<1,l,r,num);
if(l>mid)
return getnxt(mid+1,y,k<<1|1,l,r,num);
return dmin(getnxt(x,mid,k<<1,l,mid,num),getnxt(mid+1,y,k<<1|1,mid+1,r,num));
}

inline int getkth(RG int l,RG int r,RG int k){
RG int x=0,y=1e8;
while(x<=y)
getrank(1,n,1,l,r,mid) < k ?
x=mid+1:
y=mid-1;
if(getrank(1,n,1,l,r,x)>=k)
x=getpre(1,n,1,l,r,x);
return x;
}
}

int main(){
srand('K'+'a'+'i'+'b'+'a');
n=Rin(),m=Rin();
for(int i=1;i<=n;i++)
a[i]=Rin();
Seg::build(1,n,1);
while(m--){
RG int x,y,k,c=Rin();
switch(c){
case 1 :
x=Rin(),y=Rin(),k=Rin();
printf("%d\n",Seg::getrank(1,n,1,x,y,k)+1);
break;
case 2 :
x=Rin(),y=Rin(),k=Rin();
printf("%d\n",Seg::getkth(x,y,k));
break;
case 3 :
x=Rin(),k=Rin();
Seg::modify(1,n,1,x,k);
a[x]=k;
break;
case 4 :
x=Rin(),y=Rin(),k=Rin();
printf("%d\n",Seg::getpre(1,n,1,x,y,k));
break;
case 5 :
x=Rin(),y=Rin(),k=Rin();
printf("%d\n",Seg::getnxt(1,n,1,x,y,k));
break;
default : break;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: