树状数组套权值线段树

简介

我们在维护静态区间第 \(k\) 小时可以使用主席树解决,但如果区间变成动态,并含有修改,此时就需要的树套树解决

下面以P3380 【模板】树套树为例讲解

思路

树状数组套权值线段树的核心思想是用树状数组的方法处理单点修和区间查,然后在每个点上开一颗动态开点线段树来维护 \(i\sim i+lowbit(i)-1\) 的区间信息(这一点是与主席书的做法相似的)

实现

#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define ls ch[p][0]
#define rs ch[p][1]
#define lson ls,l,mid
#define rson rs,mid+1,r
#define lowbit(i) (i&-i)
const int N=1e6+5,M=3e7+5;
int tr[M],ch[M][2],rt[N],q1[N],q2[N],a[N],b[N],tot,n,m,t;
void pushup(int p){tr[p]=tr[ls]+tr[rs];}
--------------动态开点线段树-------------
void update(int& p,int l,int r,int x,int v){
	if(!p) p=++tot;
	if(l==r){tr[p]+=v;return;}
	if(x<=mid) update(lson,x,v);
	else update(rson,x,v);
	pushup(p);
}
int query_sum(int p,int l,int r,int L,int R){
	if(!p||L>R) return 0;
	if(L<=l&&r<=R) return tr[p];
	int res=0;
	if(L<=mid) res+=query_sum(lson,L,R);
	if(R>mid) res+=query_sum(rson,L,R);
	return res;
}
----------------树状数组----------------
void modify(int p,int x,int v){//单点修
	for(int i=p;i<=n;i+=lowbit(i)) 
		update(rt[i],1,m,x,v);
}
int query(int L,int R,int k){//查第k名,整体二分
	int s1=0,s2=0;
	for(int i=R;i;i-=lowbit(i)) q1[++s1]=rt[i];
	for(int i=L-1;i;i-=lowbit(i)) q2[++s2]=rt[i];
	int l=1,r=m,sum=0;
	while(l<r){
		sum=0;
		for(int i=1;i<=s1;i++) sum+=tr[ch[q1[i]][0]];
		for(int i=1;i<=s2;i++) sum-=tr[ch[q2[i]][0]];
		if(sum>=k){
			for(int i=1;i<=s1;i++) q1[i]=ch[q1[i]][0];
			for(int i=1;i<=s2;i++) q2[i]=ch[q2[i]][0];
			r=mid;
		}else{
			for(int i=1;i<=s1;i++) q1[i]=ch[q1[i]][1];
			for(int i=1;i<=s2;i++) q2[i]=ch[q2[i]][1];
			l=mid+1,k-=sum;
		}
	}
	return l;
}
int query_rk(int L,int R,int v){//查排名
	int sum=0;
	for(int i=R;i;i-=lowbit(i)) sum+=query_sum(rt[i],1,m,1,v-1);
	for(int i=L-1;i;i-=lowbit(i)) sum-=query_sum(rt[i],1,m,1,v-1);
	return sum+1;
}
struct que{int op,l,r,x;}q[N];
int main(){
	cin>>n>>t;
	for(int i=1;i<=n;i++){cin>>a[i];b[++m]=a[i];}
	for(int i=1;i<=t;i++){
		cin>>q[i].op;
		if(q[i].op==3){cin>>q[i].l>>q[i].x;} 
		else cin>>q[i].l>>q[i].r>>q[i].x;
		if(q[i].op!=2) b[++m]=q[i].x;
	}
	sort(b+1,b+m+1),m=unique(b+1,b+m+1)-b-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+m+1,a[i])-b;
		modify(i,a[i],1);
	}
	for(int i=1;i<=t;i++){
		if(q[i].op!=2) q[i].x=lower_bound(b+1,b+m+1,q[i].x)-b;
		if(q[i].op==1) cout<<query_rk(q[i].l,q[i].r,q[i].x)<<"\n";
		if(q[i].op==2) cout<<b[query(q[i].l,q[i].r,q[i].x)]<<"\n";
		if(q[i].op==3) modify(q[i].l,q[i].x,1),modify(q[i].l,a[q[i].l],-1),a[q[i].l]=q[i].x;
		if(q[i].op==4){//查前驱=排名前一个
			int res=query_rk(q[i].l,q[i].r,q[i].x);
			cout<<(res>1?b[query(q[i].l,q[i].r,res-1)]:-2147483647)<<"\n";
		}
		if(q[i].op==5){//查后继=排名后一个
			if(q[i].x==m){cout<<"2147483647\n";continue;}
			int res=query_rk(q[i].l,q[i].r,q[i].x+1);
			cout<<(res<=q[i].r-q[i].l+1?b[query(q[i].l,q[i].r,res)]:2147483647)<<"\n";
		}
	}
	return 0;
}
posted @ 2026-10-30 14:50  Rainesxiao  阅读(3)  评论(0)    收藏  举报