版权声明:存在错误或者不清楚的地方还望指出 https://blog.csdn.net/hypHuangYanPing/article/details/82860680
/**
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112
区间第k大+单点修改
对于每块进行排序,二分确定区间第k大的数;
对于单点修改,修改当前的值,并且对当前块的值进行重新排序;
时间消耗比较大;
对于主席树的解法相对来说比较耗费空间
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+7;
int n,blo,q,pos[maxn];
vector<int>vec[maxn];
int a[maxn],k;
bool judge(int l,int r,int x){
int cnt=0;
for(int i=l;i<=min(r,pos[l]*blo);i++) if(x>a[i]) cnt++;
if(pos[l]!=pos[r]){
for(int i=(pos[r]-1)*blo+1;i<=r;i++) if(x>a[i]) cnt++;
}
for(int i=pos[l]+1;i<=pos[r]-1;i++) cnt+=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
return cnt>=k;
}
int main (){
int t;scanf("%d",&t);
while(t--){
for(int i=1;i<maxn;i++) vec[i].clear();
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
blo=sqrt(n);
for(int i=1;i<=n;i++) pos[i]=(i-1)/blo+1;
for(int i=1;i<=n;i++) vec[pos[i]].push_back(a[i]);
for(int i=1;i<=pos[n];i++) sort(vec[i].begin(),vec[i].end());
char ch[3];
while(q--){
scanf("%s",ch);
if(ch[0]=='Q'){
int l,r;scanf("%d %d %d",&l,&r,&k);
int L=1,R=1e9+7,mid;//二分查找当前区间[l,r]第k大的数字;
while(R-L>1){
mid=(R+L)/2;
if(judge(l,r,mid)) R=mid;
else L=mid;
}
printf("%d\n",L);
}
else {
int id,val;scanf("%d %d",&id,&val);
int tmp=pos[id];
a[id]=val;
vec[tmp].clear();//单点修改之后,对于当前块内vec的值需要重新进行排序;
for(int i=(tmp-1)*blo+1;i<=min(n,tmp*blo);i++) vec[tmp].push_back(a[i]);
sort(vec[tmp].begin(),vec[tmp].end());
}
}
}
return 0;
}