The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.
Your task is to write a program for this computer, which
- Reads N numbers from the input (1 <= N <= 50,000)
- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.
Input
The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.
The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format
Q i j k or
C i t
It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.
There're NO breakline between two continuous test cases.
Output
For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])
There're NO breakline between two continuous test cases.
Sample Input
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
3
6
参考:
http://www.cnblogs.com/kuangbin/p/3308118.html
http://www.cnblogs.com/Rlemon/archive/2013/05/24/3096264.html
http://blog.csdn.net/acm_cxlove/article/details/8565309
思路:要是没有修改操作,直接主席树就可以了,但因为有修改操作,就要套树状数组了,每一棵主席树维护的只是某一个位置,而不是静态中的前缀和或者后缀和而这里的前缀后就交给树状数组去维护。也就是主席树维护所有位置的信息,树状数组维护前缀和。这样每次修改只需要修改logn个点
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=60010;
const int maxm=2500010;
int a[maxn],N,M,order[maxn],n,m,num;
int T[maxn],S[maxn],cnt[maxm],lson[maxm],rson[maxm];
struct Q
{
int type,l,r,x;
}qu[maxn/5];
int find(int x)
{
return lower_bound(order+1,order+m+1,x)-order;
}
int init()
{
num=0;
sort(order+1,order+n);
m=unique(order+1,order+n)-order-1;
}
int build(int l,int r)
{
int root=num++;
cnt[root]=0;
if(l!=r)
{
int mid=(l+r)>>1;
lson[root]=build(l,mid);
rson[root]=build(mid+1,r);
}
return root;
}
int insert(int root,int pos,int val)
{
int newroot=num++,tmp=newroot;
int l=1,r=m;
cnt[newroot]=cnt[root]+val;
while(l<r)
{
int mid=(l+r)>>1;
if(pos<=mid)
{
r=mid;
lson[newroot]=num++;rson[newroot]=rson[root];
newroot=lson[newroot],root=lson[root];
}
else
{
l=mid+1;
rson[newroot]=num++;lson[newroot]=lson[root];
newroot=rson[newroot],root=rson[root];
}
cnt[newroot]=cnt[root]+val;
}
return tmp;
}
int use[maxn];
int lowbit(int x)
{
return x&(-x);
}
int getsum(int x)
{
int ans=0;
while(x>0)
{
ans+=cnt[lson[use[x]]];
x-=lowbit(x);
}
return ans;
}
int query(int left,int right,int k)
{
int left_root=T[left-1];
int right_root=T[right];
int l=1,r=m;
for(int i=left-1;i>0;i-=lowbit(i))use[i]=S[i];
for(int i=right;i>0;i-=lowbit(i))use[i]=S[i];
while(l<r)
{
int mid=(l+r)>>1;
int tmp=getsum(right)-getsum(left-1)+cnt[lson[right_root]]-cnt[lson[left_root]];
if(tmp>=k)
{
r=mid;
for(int i=left-1;i>0;i-=lowbit(i))use[i]=lson[use[i]];
for(int i=right;i>0;i-=lowbit(i))use[i]=lson[use[i]];
left_root=lson[left_root];
right_root=lson[right_root];
}
else
{
k-=tmp;
l=mid+1;
for(int i=left-1;i>0;i-=lowbit(i))use[i]=rson[use[i]];
for(int i=right;i>0;i-=lowbit(i))use[i]=rson[use[i]];
left_root=rson[left_root];
right_root=rson[right_root];
}
}
return l;
}
void modify(int x,int pos,int val)
{
while(x<=N)
{
S[x]=insert(S[x],pos,val);
x+=lowbit(x);
}
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&N,&M);
n=1;
for(int i=1;i<=N;i++)
{
scanf("%d",&a[i]);
order[n++]=a[i];
}
for(int i=0;i<M;i++)
{
char op[5];
scanf("%s",op);
if(op[0]=='Q')
{
qu[i].type=0;
scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].x);
}
else
{
qu[i].type=1;
scanf("%d%d",&qu[i].l,&qu[i].x);
order[n++]=qu[i].x;
}
}
init();
T[0]=build(1,m);
for(int i=1;i<=N;i++)
T[i]=insert(T[i-1],find(a[i]),1);
for(int i=0;i<=N;i++)S[i]=T[0];
for(int i=0;i<M;i++)
{
if(qu[i].type==0)
printf("%d\n",order[query(qu[i].l,qu[i].r,qu[i].x)]);
else
{
modify(qu[i].l,find(a[qu[i].l]),-1);
modify(qu[i].l,find(qu[i].x),1);
a[qu[i].l]=qu[i].x;
}
}
}
return 0;
}