题目链接:https://www.luogu.org/problem/P2617
思路:每个树状数组的点i的都是一颗长度为lowbit(i)的主席树,为原数组【i-lowbit(i)+1,i】的信息。
/*
洛谷 P2617
两个正整数n,m分别表示序列的长度和指令的个数。
第二行有n个数,表示a[1],a[2]……a[n]
接下来的m行描述每条指令,Q i j k 或者 C i t
Q i j k 表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
C i t 表示把a[i]改变成为t。
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
ans:
3
6
*/
#include
#define M 200005
using namespace std;
int jishu=0;
int t,n,m,len_disc,tot,cl,cr;
int A[M],disc[M],L[M],R[M],K[M],root[M],LL[M],RR[M];
char S[M][2];
struct node
{
int l,r,sum;
node() {}
node(int _l,int _r,int _sum):l(_l),r(_r),sum(_sum){}
//这个地方如果改成
//node(int _l=0,int _r=0,int _sum=0):l(_l),r(_r),sum(_sum){}
//会炸内存.....改成这样内存直接加从150M左右跳到大于1000M......
//nmd老子找了一个下午的爆内存,改了这个就过了...艹
} T[600*M];
/*********主席树********/
void update(int &rt,int pos,int flag,int l,int r)//不用保存历史版本,所以可以直接修改
{
jishu++;
if(!rt) rt=++tot;
T[rt].sum+=flag;
if(l==r) return ;
int mid=(l+r)>>1;
if(pos<=mid) update(T[rt].l,pos,flag,l,mid);
else update(T[rt].r,pos,flag,mid+1,r);
}
int query(int k,int l,int r)
{
jishu++;
if(l==r) return l;
int d=0,mid=(l+r)>>1;
for(int i=1; i<=cr; i++) d+=T[T[RR[i]].l].sum;
for(int i=1; i<=cl; i++) d-=T[T[LL[i]].l].sum;
if(k<=d)
{
for(int i=1; i<=cr; i++) RR[i]=T[RR[i]].l;
for(int i=1; i<=cl; i++) LL[i]=T[LL[i]].l;
return query(k,l,mid);
}
else
{
for(int i=1; i<=cr; i++) RR[i]=T[RR[i]].r;
for(int i=1; i<=cl; i++) LL[i]=T[LL[i]].r;
return query(k-d,mid+1,r);
}
}
/*********树状数组********/
int lowbit(int x)
{
return x&(-x);
}
int add(int i,int pos,int flag)//每一个点都是一颗长为lowbit(pos)的主席树
{
jishu++;
while(i<=n)
{
update(root[i],pos,flag,1,len_disc);
i+=lowbit(i);
}
}
/*********离散化********/
void init_discate()
{
sort(disc+1,disc+1+len_disc);
len_disc=unique(disc+1,disc+1+len_disc)-disc-1;
}
int discate(int x)
{
return lower_bound(disc+1,disc+1+len_disc,x)-disc;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&A[i]),disc[++len_disc]=A[i];
for(int i=1; i<=m; i++)
{
scanf("%s",S[i]);
if(S[i][0]=='Q')
scanf("%d%d%d",&L[i],&R[i],&K[i]);
else
scanf("%d%d",&L[i],&R[i]),disc[++len_disc]=R[i];//把后边要修改的值也放去离散化
}
init_discate();
for(int i=1; i<=n; i++) add(i,discate(A[i]),1);
for(int i=1; i<=m; i++)
{
if(S[i][0]=='Q')
{
cl=0,cr=0;
for(int j=R[i]; j>0; j-=lowbit(j)) RR[++cr]=root[j];
for(int j=L[i]-1; j>0; j-=lowbit(j)) LL[++cl]=root[j];//记录树状数组对应多颗线段树的根
printf("%d\n",disc[query(K[i],1,len_disc)]);
}
else
{
add(L[i],discate(A[L[i]]),-1);
A[L[i]]=R[i];
add(L[i],discate(R[i]),1);
}
}
}