1、思路:
主席树的思想是通过建立一个区间的前缀和,用root[i]数组记录这个前缀和
每个区间内存储这个区间内有多少个数字比它小,更新时通过新建一个新的节点将之前的节点值存储在
新的节点值中,同时更新这个新的节点值,也将新的节点值变为新的前缀和的节点。
如果要修改这个主席树的一个值,需要修改前缀和即前面所有的前缀和,所以我们可以将这些前缀和用一个
树状数组来维护,以log(n)的复杂度来修改前缀和,再以log(n)的复杂度修改前缀和上的某一个节点。
2、代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1e5+10;
int root[maxn],lroot[maxn],rroot[maxn],a[maxn],n,m,tot,sz;
struct Node{
int fg,l,r,x,val;
}cur[maxn];
struct T{
int l,r,sum;
}Tree[maxn*400];
vector <int> vc;
int lowbit(int x){
return x&(-x);
}
int getid(int x){
return lower_bound(vc.begin(),vc.end(),x)-vc.begin()+1;
}
void update(int l,int r,int &rt,int x,int c){
Tree[++tot] = Tree[rt];
rt = tot;
Tree[rt].sum += c;
if(l==r) return ;
int mid = (l+r)>>1;
if(x<=mid) update(l,mid,Tree[rt].l,x,c);
else update(mid+1,r,Tree[rt].r,x,c);
}
void set(int pos,int x,int c){
while(pos<=n){ //更新所有的前缀和,这里的root[pos]就是一个树状数组
update(1,sz,root[pos],x,c);
pos += lowbit(pos);
}
}
int query(int l,int r,int L,int R,int k){
int lcnt = 0,rcnt = 0;
for(int i=L-1;i;i-=lowbit(i)){ //1~L-1范围内的修改值
lroot[++lcnt] = root[i];
}
for(int i=R;i;i-=lowbit(i)){ //1~R范围内的修改值
rroot[++rcnt] = root[i];
}
while(l<=r){ //二分缩小区间
if(l==r) return l;
int mid = (l+r)>>1,res = 0;
//记录左子树的区间个数
for(int i=1;i<=rcnt;i++){
res += Tree[Tree[rroot[i]].l].sum;
}
for(int i=1;i<=lcnt;i++){
res -= Tree[Tree[lroot[i]].l].sum;
}
if(k>res){ //在右子区间
for(int i=1;i<=rcnt;i++){
rroot[i] = Tree[rroot[i]].r;
}
for(int i=1;i<=lcnt;i++){
lroot[i] = Tree[lroot[i]].r;
}
k -= res;
l = mid+1;
}
else{ //在左子区间
for(int i=1;i<=rcnt;i++){
rroot[i] = Tree[rroot[i]].l;
}
for(int i=1;i<=lcnt;i++){
lroot[i] = Tree[lroot[i]].l;
}
r = mid;
}
}
}
int main(void){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
vc.push_back(a[i]);
}
for(int i=1;i<=m;i++){
char ss[5];
scanf("%s",ss);
if(ss[0]=='Q'){
cur[i].fg = 1;
scanf("%d%d%d",&cur[i].l,&cur[i].r,&cur[i].val);
}
else{
cur[i].fg = 2;
scanf("%d%d",&cur[i].val,&cur[i].x);
vc.push_back(cur[i].x);
}
}
sort(vc.begin(),vc.end());
vc.erase(unique(vc.begin(),vc.end()),vc.end());
sz = vc.size();
for(int i=1;i<=n;i++){
a[i] = getid(a[i]);
}
for(int i=1;i<=m;i++)
if(cur[i].fg==2){
cur[i].x = getid(cur[i].x);
}
for(int i=1;i<=n;i++){
set(i,a[i],1);
}
for(int i=1;i<=m;i++){
if(cur[i].fg==1){
printf("%d\n",vc[query(1,sz,cur[i].l,cur[i].r,cur[i].val)-1]);
}
else{
set(cur[i].val,a[cur[i].val],-1);
set(cur[i].val,cur[i].x,1);
a[cur[i].val] = cur[i].x;
}
}
return 0;
}