洛谷P1627

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int tot,n,m,ver[maxn],a[maxn],b[maxn<<1];
int ndr[maxn],ndl[maxn],cntr,cntl,len;
//可能m个全改,所以+maxn,即<<1 
struct tt{
	int l,r,val;
	//val是出现次数 
}tree[maxn<<9];
//(log n)^2 
struct ss{
	char id[3];
	int x,y,z;
}c[maxn];
int build(int l,int r){
	int rt=++tot;
	tree[rt].val=0;
	tree[rt].l=rt;
	tree[rt].r=rt;
	return rt;
}
void pushup(int root){
	tree[root].val=tree[tree[root].l].val+tree[tree[root].r].val;
}
int update(int node,int l,int r,int pos,int val){
	int root=++tot;
	tt &rt=tree[root];
	rt=tree[node];
	if(l==r){
		rt.val+=val;
		return root;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) rt.l=update(rt.l,l,mid,pos,val);
	else rt.r=update(rt.r,mid+1,r,pos,val);
	pushup(root);
	return root;
}
//p位置出现x或删去x 
void add(int x,int p,int cs){
	x=lower_bound(b+1,b+1+len,x)-b;
	//树状数组的各个下标是从1~n即n个状态,所以p的边界不是len 
	for(;p<=n;p+=p&-p)//p往上走找数组数组要更新的各位置 (状态)
		ver[p]=update(ver[p],1,len,x,cs); 
}
//求左边部分所有出现次数 
int sum(int node[],int cnt){
	int ans=0;
	for(int i=1;i<=cnt;i++)//
		ans+=tree[tree[node[i]].l].val;
		//求左边的前缀和  所以.l 
	return ans;
}
int query(int l,int r,int k){
	if(l==r) return l;
	//查询区间右-左,即lst的 - pre的 
	int tx=sum(ndr,cntr)-sum(ndl,cntl);
	int mid=(l+r)>>1;
	//够了就只看左子树,所以查询的左右边界,也只看左子树即ndlr都往左子树移 
	if(tx>=k){
		for(int i=1;i<=cntl;i++) ndl[i]=tree[ndl[i]].l;
		for(int i=1;i<=cntr;i++) ndr[i]=tree[ndr[i]].l;
		return query(l,mid,k);
	} 
	else {
		for(int i=1;i<=cntl;i++) ndl[i]=tree[ndl[i]].r;
		for(int i=1;i<=cntr;i++) ndr[i]=tree[ndr[i]].r;
		return query(mid+1,r,k-tx);
	} 
}
int ask(int l,int r,int k){
	//定义过全局了,这里也不能再定义。直接赋值即可,否则cntl,cntr更新完的值传不到全局,用不了 
	cntl=cntr=0;
	//查询区间的左边界,即pre 
	for(int p=l;p>0;p-=p&-p) ndl[++cntl]=ver[p];
	//查询区间的右边界,即lst
	for(int p=r;p>0;p-=p&-p) ndr[++cntr]=ver[p];
	return query(1,len,k);
}
int main(){
	int x,l,r,k;//len开了全局,main里面不能再定义一遍len 
		tot=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			b[i]=a[i];			
		}
		len=n;
		for(int i=1;i<=m;i++){
			scanf("%s%d%d",c[i].id,&c[i].x,&c[i].y);
			if(c[i].id[0]=='C') b[++len]=c[i].y;
			else scanf("%d",&c[i].z);
		}
		sort(b+1,b+1+len);
		len=unique(b+1,b+1+len)-(b+1);
//		memset(ver,0,sizeof(ver));  
		ver[0]=build(1,len);
		for(int i=1;i<=n;i++){		
			add(a[i],i,1);
		}
		for(int i=1;i<=m;i++){
			if(c[i].id[0]=='Q')
				printf("%d\n",b[ask(c[i].x-1,c[i].y,c[i].z)]);
			else if(a[c[i].x]!=c[i].y){
				add(a[c[i].x],c[i].x,-1);
				add(c[i].y,c[i].x,1);
				a[c[i].x]=c[i].y;
					//树里改完之后,a数组也要改。因为在下一次改的时候要看a的值 即判断a[c[i].x]!=c[i].y
			}
		}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_50904510/article/details/120035159