线段树套平衡树
因为线段树支持区间修改查询,平衡树支持查询第k大,一个数的排名,一个数的前驱、后继。所以选择两个数据结构套在一起。
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
int n,m,sz,tmp;
int a[200005],root[200005];
struct Tree
{
int l,r,num,w,s,rnd;
}tree[3000005];
void update(int &t)
{
tree[t].s=tree[tree[t].l].s+tree[tree[t].r].s+tree[t].w;
}
void lturn(int &t)//左旋
{
int k=tree[t].r;
tree[t].r=tree[k].l;
tree[k].l=t;
tree[k].s=tree[t].s;
update(t);
t=k;
}
void rturn(int &t)//右旋
{
int k=tree[t].l;
tree[t].l=tree[k].r;
tree[k].r=t;
tree[k].s=tree[t].s;
update(t);
t=k;
}
void insert(int &w,int x)//平衡树插入
{
if(!w)
{
w=++sz;
tree[w].w=1;
tree[w].s=1;
tree[w].num=x;
tree[w].rnd=rand();
return;
}
tree[w].s++;
if(x==tree[w].num) tree[w].w++;
else if(x<tree[w].num)
{
insert(tree[w].l,x);
if(tree[tree[w].l].rnd<tree[w].rnd) rturn(w);
}
else
{
insert(tree[w].r,x);
if(tree[tree[w].r].rnd<tree[w].rnd) lturn(w);
}
}
void del(int &w,int x)//平衡树删除
{
if(x==tree[w].num)
{
if(tree[w].w>1)
{
tree[w].w--;
tree[w].s--;
return;
}
if(tree[w].l*tree[w].r==0) w=tree[w].l+tree[w].r;
else if(tree[tree[w].l].rnd<tree[tree[w].r].rnd)
{
rturn(w);
del(w,x);
}
else
{
lturn(w);
del(w,x);
}
}
else if(x<tree[w].num)
{
del(tree[w].l,x);
tree[w].s--;
}
else
{
del(tree[w].r,x);
tree[w].s--;
}
}
void build(int w,int l,int r,int pos,int x)//建立线段树
{
insert(root[w],x);
if(l==r) return;
int mid=(l+r)/2;
if(pos<=mid) build(2*w,l,mid,pos,x);
else build(2*w+1,mid+1,r,pos,x);
}
void query_rank(int w,int x)//查询排名
{
if(!w) return;
if(x==tree[w].num)
{
tmp+=tree[tree[w].l].s;
return;
}
else if(x<tree[w].num) query_rank(tree[w].l,x);
else
{
tmp+=tree[tree[w].l].s+tree[w].w;
query_rank(tree[w].r,x);
}
}
void ask_rank(int w,int L,int R,int l,int r,int v)//线段树中寻找
{
if(l==L && r==R)
{
query_rank(root[w],v);
return;
}
int mid=(L+R)/2;
if(r<=mid) ask_rank(2*w,L,mid,l,r,v);
else if(l>mid) ask_rank(2*w+1,mid+1,R,l,r,v);
else
{
ask_rank(2*w,L,mid,l,mid,v);
ask_rank(2*w+1,mid+1,R,mid+1,r,v);
}
}
void ask_val(int x,int y,int z)//二分找到这个值
{
int l=0,r=999999999,ans;
while (l<=r)
{
int mid=(l+r)/2;
tmp=1;
ask_rank(1,1,n,x,y,mid);
if (tmp<=z) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",ans);
}
void change(int w,int l,int r,int pos,int x1,int x2)//修改值
{
del(root[w],x2);
insert(root[w],x1);
if(l==r) return;
int mid=(l+r)/2;
if(pos<=mid) change(2*w,l,mid,pos,x1,x2);
else change(2*w+1,mid+1,r,pos,x1,x2);
}
void before(int w,int x)//前驱
{
if(!w) return;
if(tree[w].num<x)
{
tmp=max(tmp,tree[w].num);
before(tree[w].r,x);
}
else before(tree[w].l,x);
}
void after(int w,int x)//后继
{
if(!w) return;
if(tree[w].num>x)
{
tmp=min(tmp,tree[w].num);
after(tree[w].l,x);
}
else after(tree[w].r,x);
}
void ask_before(int w,int L,int R,int l,int r,int v)
{
if(l==L && r==R)
{
before(root[w],v);
return;
}
int mid=(L+R)/2;
if(r<=mid) ask_before(2*w,L,mid,l,r,v);
else if(l>mid) ask_before(2*w+1,mid+1,R,l,r,v);
else
{
ask_before(2*w,L,mid,l,mid,v);
ask_before(2*w+1,mid+1,R,mid+1,r,v);
}
}
void ask_after(int w,int L,int R,int l,int r,int v)
{
if(l==L && r==R)
{
after(root[w],v);
return;
}
int mid=(L+R)/2;
if(r<=mid) ask_after(2*w,L,mid,l,r,v);
else if(l>mid) ask_after(2*w+1,mid+1,R,l,r,v);
else
{
ask_after(2*w,L,mid,l,mid,v);
ask_after(2*w+1,mid+1,R,mid+1,r,v);
}
}
int main()
{
freopen("bzoj3196.in","r",stdin);
freopen("bzoj3196.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
build(1,1,n,i,a[i]);
for(int i=1;i<=m;i++)
{
int op,l,r,pos,k;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&l,&r,&k);
tmp=1;
ask_rank(1,1,n,l,r,k);
printf("%d\n",tmp);
}
if(op==2)
{
scanf("%d%d%d",&l,&r,&k);
ask_val(l,r,k);
}
if(op==3)
{
scanf("%d%d",&pos,&k);
change(1,1,n,pos,k,a[pos]);
a[pos]=k;
}
if(op==4)
{
scanf("%d%d%d",&l,&r,&k);
tmp=0;
ask_before(1,1,n,l,r,k);
printf("%d\n",tmp);
}
if(op==5)
{
scanf("%d%d%d",&l,&r,&k);
tmp=99999999;
ask_after(1,1,n,l,r,k);
printf("%d\n",tmp);
}
}
return 0;
}