题目:
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问: 对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1) 并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。
Input
第一个数表示数据组数。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。 第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。 接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。 C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Output:
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
解题思路:
首先,我们得知道,一段区间第K大的数只大于等于区间内中的K个数.故只用二分查找出最小的数在这个区间内正好有K个数小于等于它即可. 对于每一个块都维护顺序(即对每一个块的内部元素排序)以便之后可以快速得出这个块内小于等于一个值的元素有多少个.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define M 1000000000//数值上限
using namespace std;
int S,P[60005],B[60005],C[60005];
struct node {
int id,d;
bool operator <(const node &_) {
return d<_.d;
}
} A[61005];
void turn(int i,int t) {
int k=i/S;
A[P[i]].d=t;
B[i]=t;
sort(A+k*S,A+(k+1)*S);
for(int i=k*S; i<(k+1)*S; i++)P[A[i].id]=i,C[i]=A[i].d;//每次排序后都要维护编号
}
int find(int l,int r,int d) {
int ka=l/S,kb=r/S;//块编号
if(ka==kb) {
return B[r-d+1];
} else {
//return 0;
int L=0,R=M,ans=0;
while(L<=R) {
int mid=(L+R)>>1,sum=0;
//printf("!%d %d\n",L,R);
for(int i=l; i<(ka+1)*S; i++)sum+=(B[i]<=mid);
for(int i=kb*S; i<=r; i++)sum+=(B[i]<=mid);//统计残缺快内小于等于mid的数
//puts("!");
for(int i=ka+1; i<kb; i++)sum+=upper_bound(C+i*S,C+i*S+S,mid)-C-i*S;//查找C内有多少个小于等于mid的数.
if(sum>=d)ans=mid,R=mid-1;
else L=mid+1;
}
return ans;
}
}
char s[5];
int main() {
int T;
scanf("%d",&T);
while(T--) {
int n,m,k;
scanf("%d%d",&n,&m);
if(n==1) {//特判,能不能删掉,读者自行尝试.
S=1;
k=1;
}else{
S=sqrt(n*log(n)/log(2));//最优的块的大小
//printf("%d\n",S);
k=n/S;
}
//printf("k=%d\n",k);
for(int i=1; i<=n; i++)scanf("%d",&A[i].d),A[i].id=i,B[i]=A[i].d;//B内存正确顺序的元素的值
//sort(A+1,A+S);
A[0].d=0;
A[0].id=0;
for(int i=0; i<=k; i++) {
//printf("%d %d\n",S*i,(i+1)*S-1);
sort(A+S*i,A+(i+1)*S);//初始化块内元素有序
}
//for(int i=1; i<=n; i++)printf("%d ",A[i].d);
for(int i=1; i<=n; i++)P[A[i].id]=i,C[i]=A[i].d;//P为元素的编号与其排序后的位置的一个映射
//puts("");
while(m--) {
scanf("%s",s);
if(s[0]=='C') {
int a,d;
scanf("%d%d",&a,&d);
turn(a,d);
} else {
int l,r,d;
scanf("%d%d%d",&l,&r,&d);
printf("%d\n",find(l,r,d));
}
}
}
return 0;
}