/*给定n个数,可以动态修改某个数,随时查询某个区间第k大的值。
http://blog.csdn.net/regina8023/article/details/41911837
树状数组套主席树。
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define maxn 10005
using namespace std;
int use[maxn*10],n,m,size,tot=0,all=0,h[maxn*10],v[maxn*10],t[maxn*10];
struct chairtree
{
int l,r,size; //size保存[l,r]区间数据的个数
}a[maxn*300];
//记录输入的m条指令
struct question
{
int l,r,k;
}q[maxn];
//树状数组
int lowbit(int x)
{
return x&(-x);
}
//对数组h排序,并求出有多少个不同的值
void Hash1()
{
sort(h+1,h+1+all);
size=unique(h+1,h+1+all)-h-1;
}
//求出x在去重后的数据中的序号
int Hash(int x)
{
return lower_bound(h+1,h+1+size,x)-h;
}
//建线段树
int Build(int l,int r)
{
int now=++tot;
a[now].size=0;
if (l==r) return now;
int m=(l+r)>>1;
a[now].l=Build(l,m);
a[now].r=Build(m+1,r);
return now;
}
//更新。每更新一个节点相当于建立新的线段树
//非递归更新
//val为1或-1.表示删除数据或新增数据
//修改数据:要先删除然后再增加
int Update(int root,int p,int val)
{
int now=++tot,tmp=now;
int l=1,r=size;
a[now].size=a[root].size+val; //now是新节点
while (l<r) //非递归更新
{
int m=(l+r)>>1;
if (p<=m) //左子树新增节点
{
a[now].l=++tot; a[now].r=a[root].r;
root=a[root].l; now=a[now].l;
r=m;
}
else //右子树新增节点
{
a[now].l=a[root].l; a[now].r=++tot;
root=a[root].r; now=a[now].r;
l=m+1;
}
a[now].size=a[root].size+val;
}
return tmp;
}
//把第x个数改成p(p已经离散化为去重后的序号)
//val为1或-1
void Add(int x,int p,int val)
{
printf("Add:%d ->%d %d Change:",x,p,val);
for (int i=x;i<=n;i+=lowbit(i)) //树状数组只需修改logn个
{
t[i]=Update(t[i],p,val);
printf("%d ",i);
}
printf("\n");
}
//统计与x相关的树状数组对应的主席树的左子树个数
//因为要找第k大的元素,只计算左边就可以知道第k大的数是在左还是在右
int Getsum(int x)
{
int ans=0;
for (int i=x;i;i-=lowbit(i))
ans+=a[a[use[i]].l].size;
return ans;
}
//查询区间 [lx,rx]的第k个数
int Query(int lx,int rx,int k)
{
int l=1,r=size;
//求出rx,lx-1对应的树状数组+主席树
for (int i=lx-1;i;i-=lowbit(i)) use[i]=t[i];
for (int i=rx;i;i-=lowbit(i)) use[i]=t[i];
while (l<r)
{
int m=(l+r)>>1;
int tmp=Getsum(rx)-Getsum(lx-1);
if (tmp>=k) //第k大的数在左子树,往左子树走
{
for (int i=lx-1;i;i-=lowbit(i))
use[i]=a[use[i]].l;
for (int i=rx;i;i-=lowbit(i))
use[i]=a[use[i]].l;
r=m;
}
else //往右子树走
{
for (int i=lx-1;i;i-=lowbit(i))
use[i]=a[use[i]].r;
for (int i=rx;i;i-=lowbit(i))
use[i]=a[use[i]].r;
k-=tmp;
l=m+1;
}
}
return l;
}
int main()
{
freopen("a.txt","r",stdin);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&v[i]),h[i]=v[i];
all=n;
for (int i=1;i<=m;i++)
{
char str[10];
int l,r,k;
scanf("%s",str);
if (str[0]=='Q')
{
scanf("%d%d%d",&l,&r,&k); //查询[l,r]区间第k大的数
q[i].l=l,q[i].r=r,q[i].k=k;
}
else
{
scanf("%d%d",&r,&k); //把第r个数改为k
q[i].l=0,q[i].r=r,q[i].k=k;
h[++all]=k;
}
}
//h数组记录了全部数据(包括后面要修改的数据)
Hash1(); //去掉重复的数据,size为不相同的数据个数
//对每个数据建立一棵树(主席树)
t[0]=Build(1,size);
for (int i=1;i<=n;i++)
t[i]=t[0];
//按顺序把原数据增加到对应的主席树
//同时修改多棵树 lowbit(x)
for (int i=1;i<=n;i++)
Add(i,Hash(v[i]),1);
//处理给出的指令
for (int i=1;i<=m;i++)
{
if (q[i].l)
{
printf("%d\n",h[Query(q[i].l,q[i].r,q[i].k)]);
}
else
{
Add(q[i].r,Hash(v[q[i].r]),-1); //先把原数去掉
Add(q[i].r,Hash(q[i].k),1); //增加新数
v[q[i].r]=q[i].k; //v数组保存最新的数据
}
}
return 0;
}