LUOGU P2617 Dynamic Rankings(树状数组套主席树)

传送门

解题思路

  动态区间第\(k\)大,树状数组套主席树模板。树状数组的每个位置的意思的是每棵主席树的根,维护的是一个前缀和。然后询问的时候\(log\)个点一起做前缀和,一起移动。时空复杂度\(O(nlog^2n)\)

代码


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;
const int N=100005;
const int M=200005*18*18;

inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;	
}

int n,m,tmp[25][2],a[N],cpy[N<<1],u,cnt,rt[N];
int cnt0,cnt1;
struct Segment_tree{
	int ls,rs,w;	
}t[M];
struct Ask{
	int op,l,r,k;	
}q[N];

void update(int &x,int l,int r,int pos,int val){
	if(!x) x=++cnt;t[x].w+=val;
	if(l==r) return ;int mid=(l+r)>>1;
	if(pos<=mid) update(t[x].ls,l,mid,pos,val);
	else update(t[x].rs,mid+1,r,pos,val);
}	

inline void prepare_update(int x,int val){
	int now=lower_bound(cpy+1,cpy+1+u,a[x])-cpy;
	for(int i=x;i<=n;i+=i&-i) update(rt[i],1,u,now,val);
}

int query(int l,int r,int k){
	if(l==r) return l;int sum=0,mid=(l+r)>>1;
	for(int i=1;i<=cnt1;i++) sum+=t[t[tmp[i][1]].ls].w;
	for(int i=1;i<=cnt0;i++) sum-=t[t[tmp[i][0]].ls].w;
	if(sum>=k){
		for(int i=1;i<=cnt0;i++) tmp[i][0]=t[tmp[i][0]].ls;
		for(int i=1;i<=cnt1;i++) tmp[i][1]=t[tmp[i][1]].ls;
		return query(l,mid,k);
	}	
	else {
		for(int i=1;i<=cnt0;i++) tmp[i][0]=t[tmp[i][0]].rs;
		for(int i=1;i<=cnt1;i++) tmp[i][1]=t[tmp[i][1]].rs;
		return query(mid+1,r,k-sum);
	}
}	

inline int prepare_query(int l,int r,int k){
	memset(tmp,0,sizeof(tmp));cnt0=cnt1=0;
	for(int i=l-1;i;i-=i&-i) tmp[++cnt0][0]=rt[i];
	for(int i=r;i;i-=i&-i) tmp[++cnt1][1]=rt[i];
	return query(1,u,k);
}	

int main(){
	n=rd(),m=rd();char c;int num=n;
	for(int i=1;i<=n;i++) cpy[i]=a[i]=rd();
	for(int i=1;i<=m;i++) {
		c=' ';while(c!='Q' && c!='C') c=getchar();
		if(c=='C') q[i].op=1,q[i].l=rd(),q[i].k=rd(),cpy[++num]=q[i].k;
		else q[i].op=2,q[i].l=rd(),q[i].r=rd(),q[i].k=rd(); 
	}
	sort(cpy+1,cpy+1+num);
	u=unique(cpy+1,cpy+1+num)-cpy-1;
	for(int i=1;i<=n;i++) prepare_update(i,1);
	for(int i=1;i<=m;i++){
		if(q[i].op==1){
			prepare_update(q[i].l,-1);
			a[q[i].l]=q[i].k;
			prepare_update(q[i].l,1);
		}
		else printf("%d\n",cpy[prepare_query(q[i].l,q[i].r,q[i].k)]);	
	}	
	return 0;	
}

posted @ 2019-01-06 22:59  Monster_Qi  阅读(112)  评论(0编辑  收藏  举报