To_Heart—模板——整体二分

#include<bits/stdc++.h>
using namespace std;

int n,m;
int a[2000005];
int ans[2000005];
char s[5];
struct zz{ int op,l,r,k,id;} q[2000005],q1[2000005],q2[2000005];
struct BIT{
	int bit[2000005];
	int Lowbit(int x){ return x&(-x); }
	void Insert(int x,int val){ while(x<=n) bit[x]+=val,x+=Lowbit(x); }
	int Find(int x){ int ans=0; while(x) ans+=bit[x],x-=Lowbit(x); return ans; } 
}T;																				//李家祖传树状数组,无双战魂。 

void Solve(int l,int r,int L,int R){
	if(l>r||L>R) return ;
	if(l==r){ for(int i=L;i<=R;i++) if(q[i].op) ans[q[i].id]=l; return ; }
	int tot1=0,tot2=0,mid=(l+r)>>1;
	for(int i=L;i<=R;i++){
		if(q[i].op){
			int now=T.Find(q[i].r)-T.Find(q[i].l-1);
			if(now>=q[i].k)	q1[++tot1]=q[i];
			else tot2++,q2[tot2]=q[i],q2[tot2].k-=now;                          //把查询分开 
		}
		else{
			if(q[i].k<=mid) T.Insert(q[i].l,q[i].r),q1[++tot1]=q[i];
			else q2[++tot2]=q[i];												//把修改分为两部分,大于 mid 的只会在值域为 mid~r 的区间产生影响。 
		} 
	}
	for(int i=L;i<=R;i++) if(!q[i].op&&q[i].k<=mid) T.Insert(q[i].l,-q[i].r);	//还原树状数组 
	for(int i=1;i<=tot1;i++) q[L+i-1]=q1[i];
	for(int i=1;i<=tot2;i++) q[L+tot1+i-1]=q2[i];								//把序列还原,为递归做准备 
	Solve(l,mid,L,L+tot1-1);Solve(mid+1,r,L+tot1,R);							//二分值域 
}

int main(){
	cin>>n>>m;int tot=0,cnt=0;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),q[++tot]=(zz){0,i,1,a[i],0};		//把一开始的序列*成插入,这样就不用考虑原序列了 
	for(int i=1;i<=m;i++){
		int l,r,k;scanf("%s",s+1);
		if(s[1]=='Q') scanf("%d%d%d",&l,&r,&k),q[++tot]=(zz){1,l,r,k,++cnt};
		else scanf("%d%d",&l,&r),q[++tot]=(zz){0,l,-1,a[l],0},q[++tot]=(zz){0,l,1,r,0},a[l]=r;		//修改拆成删除和添加,方便数据结构的维护。 
	}
	Solve(-1,1000000000,1,tot);
	for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2022-02-16 21:30  To_Heart  阅读(2)  评论(0编辑  收藏  举报  来源