学习心得 - 算法 - 整体二分
主体思想
把多个查询一起解决。
适合解决区间
全局第 k 小
- 可以直接排序。
- 二分值域,维护
\leq mid 数个数 - 把所有询问放在一起二分 (整体二分)。
执行
计算 solve(l,r),询问中的答案都在
猜测答案
在序列
具体来说:
把输入序列
对于
否则分治。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int tr[N<<2],n,m,qc;
int lowbit(int x){
return x&-x;
}
void update(int x,int v){
for(;x<=qc;x+=lowbit(x))tr[x]+=v;
}
int query(int x){
int su=0;
for(;x>=1;x-=lowbit(x))su+=tr[x];
return su;
}
struct qry{
int op,x,y,k,i;
}q[N],ql[N],qr[N];
int ans[N];
void solve(int l,int r,int nl,int nr){
if(nl>nr)return;
if(l==r){
for(int i=nl;i<=nr;i++)
ans[q[i].i]=l;
return;
}
int mid=(l+r)>>1,cur1=0,cur2=0;
for(int i=nl;i<=nr;i++){
if(q[i].op==1){ // Insert
if(q[i].y<=mid)
ql[++cur1]=q[i],
update(q[i].x,q[i].k);
else qr[++cur2]=q[i];
}else{
int res=query(q[i].y)-query(q[i].x-1);
if(q[i].k<=res)
ql[++cur1]=q[i];
else
qr[++cur2]=q[i],qr[cur2].k-=res;
}
}
for(int i=nl;i<=nr;i++)if(q[i].op==1&&q[i].y<=mid)
update(q[i].x,-q[i].k);
for(int i=1;i<=cur1;i++)q[i+nl-1]=ql[i]; // Copy Left
for(int i=1;i<=cur2;i++)q[i+nl-1+cur1]=qr[i]; // Copy Right
// Solve
solve(l,mid,nl,nl+cur1-1);
solve(mid+1,r,nl+cur1,nr);
}
char op;
int a[N],x,y,k,qs;
bool isq[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i],q[++qc]={1,i,a[i],1,0};
for(int i=1;i<=m;i++){
cin>>op>>x>>y;
if(op=='Q'){
cin>>k;
q[++qc]={2,x,y,k,++qs};
isq[i]=1;
}else q[++qc]={1,x,a[x],-1,0},q[++qc]={1,x,a[x]=y,1,0};
}
solve(-1e9,1e9,1,qc);
for(int i=1;i<=qs;i++)
cout<<ans[i]<<"\n";
return 0;
}