前置知识:整体二分
这道题在整体二分模版题的基础上又增加了一个单点的修改,实际上很简单,既然是单点修改那么就在查的时候改就行了。
具体怎么改呢?比如维护数量的树状数组里
b
i
t
[
x
]
bit[x]
bit[x]的值为
1
1
1,但是我们有一个修改操作要将
x
x
x改为
y
y
y,所以可以考虑以下方法:
1,因为值
x
x
x被改动了,所以原来关于
x
x
x的一切值就废了,所以就将树状数组中
b
i
t
[
x
]
bit[x]
bit[x]的值加上
−
b
i
t
[
x
]
-bit[x]
−bit[x],然后就可以把他的值消掉嘞。
2,接着,要把
x
x
x改为
y
y
y,再将树状数组中
b
i
t
[
y
]
bit[y]
bit[y]的值加上
b
i
t
[
x
]
bit[x]
bit[x]。
#include<bits/stdc++.h>
#define xx x&-x
using namespace std;
const int N=1e6+5;
const int M=1e3+5;
int n,m;
struct node{
int l,r,k,id,op;
}a[N],ql[N],qr[N];
int answer[N];
int bit[N];
int cnt;
void change(int x,int p){
while(x<=cnt){
bit[x]+=p;
x+=xx;
}
}
int query(int x){
int res=0;
while(x){
res+=bit[x];
x-=xx;
}
return res;
}
void f(int l,int r,int N,int M){
if(N>=M)return;
if(l==r){
for(int i=N;i<=M;i++){
if(a[i].op==2)answer[a[i].id]=r;
}
return;
}
int mid=l+r>>1;
int t1=0,t2=0;
for(int i=N;i<=M;i++){
if(a[i].op==1){
if(mid>=a[i].l){
ql[++t1]=a[i];
change(a[i].id,a[i].k);//a[i].k存储了是删除还是增加
}
else{
qr[++t2]=a[i];
}
}
else{
int x=query(a[i].r)-query(a[i].l-1);
if(x>=a[i].k){
ql[++t1]=a[i];
}
else{
a[i].k-=x;
qr[++t2]=a[i];
}
}
}
for(int i=1;i<=t1;i++){
a[i+N-1]=ql[i];
if(ql[i].op==1)change(ql[i].id,-ql[i].k);//与上面同理
}
for(int i=1;i<=t2;i++){
a[i+N+t1-1]=qr[i];
}
f(l,mid,N,N+t1-1);
f(mid+1,r,N+t1,M);
}
int p[N];
int idx;
signed main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].l;
a[i].id=i;
a[i].op=1;
a[i].k=1;
p[i]=a[i].l;
}
cnt=n;
for(int i=1;i<=m;i++){
cnt++;
char op;
cin>>op;
if(op=='Q'){
cin>>a[cnt].l>>a[cnt].r>>a[cnt].k;
a[cnt].id=++idx;
a[cnt].op=2;
}
else{
int l,r;
cin>>l>>r;
a[cnt]=node{p[l],0,-1,a[l].id,1};//清除
p[l]=r;
a[++cnt]=node{p[l],0,1,a[l].id,1};//增加
}
}
f(-1e9,1e9,1,cnt);
for(int i=1;i<=idx;i++)cout<<answer[i]<<'\n';
}