二逼平衡树[树套树模板]

题目描述

您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:

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

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

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

  4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

  5. 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

输入格式:

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

[树套树]

我们熟知,平衡树可以查询整个数列的第K大,但是不能查询部分序列

线段树可以提取某个区间

于是线段树+平衡树即树套树可以支持部分区间的第K大,前驱,后继...

如何实现呢

树套树是一种很暴力的数据结构

可能没有懂... 

通俗解释一下----

1--4 区间对应的Treap里有4个值, 1--2 区间对应的Treap有2个值....

我们每插入一个节点都要把到线段树最底下的路径上的点对应的Treap都插入一个它

 比如说我们要在3这个位置插入一个4

从线段树的根到3要经过的区间有 1--4, 3--4,3--3

于是这3个区间对应的Treap都会插入一个4这个值

这样做有什么好处呢?? 如果我们要查询2--4的信息,我们递归找到2--2,3--4 

到3--4就不用再找了,可以直接从3--4区间的Treap中查询答案

root[i]有什么用呢??

3--4区间对应线段树上的值是3,而3--4区间的Treap的根可能是9

我们记录rt[3]=9 , 如果要查询3--4 这个区间,我们只需要直接在Treap中查(rt[3],...)


代码

#include<bits/stdc++.h>
#define N 100005
#define inf 2147483647
#define lc tr[x].ch[0]
#define rc tr[x].ch[1]
using namespace std;
int a[N],rt[N<<2],ans;
struct Node{int l,r,val;}t[N<<2];
struct Treap{int ch[2],val,p,size,num;}tr[N*20];
int n,m,tot;
int read(){
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
	return cnt*f;
}
int randon(){
	static int seed=233;
	return seed=int(seed*47281LL%0x3fffffff);
}
void Pushup(int x){
	tr[x].size=tr[lc].size+tr[rc].size+tr[x].num; 
}
void rotate(int &x,int k){
	int y=tr[x].ch[k];
	tr[x].ch[k]=tr[y].ch[k^1];
	tr[y].ch[k^1]=x; 
	tr[y].size=tr[x].size;
	Pushup(x); x=y;
}
void insert(int &x,int val){
	if(!x){x=++tot;tr[x].val=val,tr[x].size=tr[x].num=1,tr[x].p=randon();return;}
	tr[x].size++;
	if(tr[x].val==val){tr[x].num++;return;}
	if(val<tr[x].val){
		insert(lc,val);
		if(tr[lc].p<tr[x].p) rotate(x,0);
	}
	else{
		insert(rc,val);
		if(tr[rc].p<tr[x].p) rotate(x,1);
	}
}
void erase(int &x,int val){
	if(!x) return;
	if(tr[x].val==val){
		if(tr[x].num>1) tr[x].num--,tr[x].size--;
		else if(lc*rc==0) x=lc+rc;
		else{
			if(tr[lc].p<tr[rc].p) rotate(x,0);
			else rotate(x,1);
			erase(x,val);
		}
	}    
	else{	
		tr[x].size--;
		if(val<tr[x].val) erase(lc,val);
		else erase(rc,val);
	}
}
void rank(int x,int k){
    if(!x) return;
    if(tr[x].val==k) ans+=tr[lc].size;
    else if(k<tr[x].val) rank(lc,k);
    else ans+=tr[lc].size+tr[x].num,rank(rc,k);
}
void Build(int x,int l,int r,int pos,int val){
	t[x].l=l,t[x].r=r;
	insert(rt[x],val);
	if(l==r) return;
	int mid=(l+r)>>1;
	if(pos<=mid) Build(x<<1,l,mid,pos,val);
	else Build(x<<1|1,mid+1,r,pos,val);
}
void Rank(int x,int L,int R,int k){
	if(L<=t[x].l&&t[x].r<=R){rank(rt[x],k);return;}
	int mid=(t[x].l+t[x].r)>>1;
	if(L<=mid) Rank(x<<1,L,R,k);
	if(R>mid) Rank(x<<1|1,L,R,k);
} 
void Kth(int L,int R,int k){
	int l=1,r=inf;
	while(l<r){
		int mid=(l+r+1)>>1;
		ans=1,Rank(1,L,R,mid);
		if(ans<=k) l=mid;
		else r=mid-1;
	}
	printf("%d\n",l);
}
void Change(int x,int pos,int last,int val){
	erase(rt[x],last);
	insert(rt[x],val);
	if(t[x].l==t[x].r) return;
	int mid=(t[x].l+t[x].r)>>1;
	if(pos<=mid) Change(x<<1,pos,last,val);
	else Change(x<<1|1,pos,last,val);
}
void Pre(int x,int val){
	if(!x) return;
	if(tr[x].val<val){
		ans=max(ans,tr[x].val),Pre(rc,val);
	}
	else Pre(lc,val);
}
void Suf(int x,int val){
	if(!x) return;
	if(val<tr[x].val){
		ans=min(ans,tr[x].val),Suf(lc,val);
	}
	else Suf(rc,val);
}
void Ask(int op,int x,int L,int R,int k){
	if(L<=t[x].l&&t[x].r<=R){
		if(op==1) Pre(rt[x],k);
		else Suf(rt[x],k);
		return;
	}
	int mid=(t[x].l+t[x].r)>>1;
	if(L<=mid) Ask(op,x<<1,L,R,k);
	if(R>mid) Ask(op,x<<1|1,L,R,k); 
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		a[i]=read(),Build(1,1,n,i,a[i]); 
	}
	while(m--){
		int op=read(),x=read(),y=read();
		if(op==1){
			int k=read();
			ans=1,Rank(1,x,y,k);
			printf("%d\n",ans);
		}
		if(op==2){
			int k=read();
			Kth(x,y,k);
		}
		if(op==3) Change(1,x,a[x],y),a[x]=y;
		if(op==4){
			int k=read(); 
			ans=-inf,Ask(1,1,x,y,k); 
			printf("%d\n",ans);
		}
		if(op==5){
			int k=read();
			ans=inf,Ask(2,1,x,y,k);
			printf("%d\n",ans);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/83152310
今日推荐