树套树之线段树套平衡树问题
主要解决以下几类问题
1、查询k在[l,r]的排名;对treap原来的求排名函数稍作修改为求比k小的数的个数。这样线段树分段查询再合并加1,就是k在l-r的排名。
时间复杂度:(log2n)[线段树,平衡树]
2、查询在[l,r]的区间中排名为k的元素。这个操作真没有什么高深的做法,二分值大小吧,再用操作一暴力。听说隔壁“线段树/树状数组套主席树”可以只带两个log,平衡树表示无奈。
时间复杂度:(log3n)[二分,线段树,平衡树]
3、将位置为pos的元素值修改为k。这个也很简单(暴力),线段树枚举pos所在的log个区间,每次从平衡树中删去原值,插入新值。
4、查找k在[l,r]中的前驱(要求严格小于)。线段树划分区间,再用平衡树暴力求各区间的前驱,最后合并前驱。
5、查询k在[l,r]中的后继(要求严格大于)。对操作四依葫芦画瓢。
例题CDUTCM1562:区间查询
线段树套平衡树的模板题
AC代码
#include<bits/stdc++.h>
#define ls t[x].ch[0]
#define rs t[x].ch[1]
using namespace std;
const int inf=2147483647;
const int maxn=5e4+1000;
int n,m;
int p[maxn];
struct node{
int val,key,cnt,size;
int ch[2];
};
node t[maxn*40];
int tot;
struct treap{
int root;
void update(int x){
t[x].size=t[ls].size+t[rs].size+t[x].cnt;
}
void rotate(int &x,int d){
int son=t[x].ch[d];
t[x].ch[d]=t[son].ch[d^1];
t[son].ch[d^1]=x;update(x);update(x=son);
}
void insert(int &x,int val){
if(!x){
x=++tot;
t[x].cnt=t[x].size=1;
t[x].key=rand(),t[x].val=val;
return ;
}
t[x].size++;
if(t[x].val==val){t[x].cnt++;return;}
int d=val>t[x].val;insert(t[x].ch[d],val);
if(t[x].key>t[t[x].ch[d]].key) rotate(x,d);
}
void delet(int &x,int val){
if(!x) return ;
if(t[x].val==val){
if(t[x].cnt>1){t[x].cnt--,t[x].size--;return ;}
bool d=t[ls].key>t[rs].key;
if(ls==0||rs==0) x=ls+rs;
else rotate(x,d),delet(x,val);
}
else t[x].size--,delet(t[x].ch[t[x].val<val],val);
}
int rank(int x,int val){
if(!x)return 0;
if(t[x].val==val) return t[ls].size;
if(t[x].val>val) return rank(ls,val);
else return t[ls].size+t[x].cnt+rank(rs,val);
}
int kth(int x,int k){
while(1){
if(k<=t[ls].size)x=ls;
else if(k>t[ls].size+t[x].cnt) k-=t[ls].size+t[x].cnt,x=rs;
else return t[x].val;
}
}
int pre(int x,int val){
if(!x) return -inf;
if(t[x].val>=val) return pre(ls,val);
else return max(t[x].val,pre(rs,val));
}
int nxt(int x,int val){
if(!x) return inf;
if(t[x].val<=val) return nxt(rs,val);
else return min(t[x].val,nxt(ls,val));
}
}a[maxn<<2];
inline void read(int &x){
x=0;
char tmp=getchar();
while(tmp<'0'||tmp>'9')
tmp=getchar();
while(tmp>='0'&&tmp<='9')
x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
inline void read(int &x,int &y){read(x),read(y);}
inline void read(int &x,int &y,int &z){read(x),read(y),read(z);}
void build(int x,int l,int r){
for(int i=l;i<=r;i++)
a[x].insert(a[x].root,p[i]);
if(l==r) return ;
build(x<<1,l,l+r>>1);
build(x<<1|1,(l+r>>1)+1,r);
}
int queryrank(int x,int l,int r,int ql,int qr,int num){
if(l>qr||r<ql) return 0;
if(ql<=l&&r<=qr)
return a[x].rank(a[x].root,num);
int ret=0;
ret+=queryrank(x<<1,l,l+r>>1,ql,qr,num);
ret+=queryrank(x<<1|1,(l+r>>1)+1,r,ql,qr,num);
return ret;
}
int queryval(int ql,int qr,int k){
int l=0,r=1e8,mid,ans=-1;
while(l<=r){
mid=l+r>>1;
if(queryrank(1,1,n,ql,qr,mid)+1<=k)ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
void modify(int x,int l,int r,int pos,int k){
if(pos<l||r<pos) return ;
a[x].delet(a[x].root,p[pos]);
a[x].insert(a[x].root,k);
if(l==r) return ;
modify(x<<1,l,l+r>>1,pos,k);
modify(x<<1|1,(l+r>>1)+1,r,pos,k);
}
int querypre(int x,int l,int r,int ql,int qr,int k){
if(l>qr||r<ql) return -inf;
if(ql<=l&&r<=qr) return a[x].pre(a[x].root,k);
int ret=querypre(x<<1,l,l+r>>1,ql,qr,k);
ret=max(ret,querypre(x<<1|1,(l+r>>1)+1,r,ql,qr,k));
return ret;
}
int querynxt(int x,int l,int r,int ql,int qr,int k){
if(l>qr||r<ql) return inf;
if(ql<=l&&r<=qr) return a[x].nxt(a[x].root,k);
int ret=querynxt(x<<1,l,l+r>>1,ql,qr,k);
ret=min(ret,querynxt(x<<1|1,(l+r>>1)+1,r,ql,qr,k));
return ret;
}
int main(){
srand(19260817);
cin>>n>>m;
for(int i=1;i<=n;i++)read(p[i]);
build(1,1,n);
char op;
for(int i=1;i<=m;i++){
int l,r,k,pos;
scanf("%c",&op);
/* if(op==1){ //查询k在[l,r]的排名
read(l,r,k);
printf("%d\n",queryrank(1,1,n,l,r,k)+1);
}*/
if(op=='Q'){ //查询在[l,r]的区间中排名为k的元素
read(l,r,k);
printf("%d\n",queryval(l,r,k));
}
else if(op=='C'){ //将位置为pos的元素值修改为k。
read(pos,k);
modify(1,1,n,pos,k);p[pos]=k;
}
/*
else if(op==4){ //查找k在[l,r]中的前驱(要求严格小于)。
read(l,r,k);
printf("%d\n",querypre(1,1,n,l,r,k));
}
else{ //查询k在[l,r]中的后继(要求严格大于)
read(l,r,k);
printf("%d\n",querynxt(1,1,n,l,r,k));
}
*/
}
return 0;
}
/**************************************************************
Problem: 1562
User: 201744901029
Language: C++
Result: 正确
Time:316 ms
Memory:50840 kb
****************************************************************/