题意:
有一个长度为n的序列a,一开始所有数为0,
q次操作,操作有两种:
(C x v):将a[x]修改为v
(Q l r):问[l,r]中第8大的数
数据范围:n,q<=1e5,0<=a(i)<=1e9
解法:
问题可以离线,因此可以整体二分。
ps:
这题树套树也可以做,但是整体二分省空间
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
struct QQ{
int op,x,y,k,id;
}Q[maxm],lc[maxm],rc[maxm];
int mark[maxm];
int ans[maxm];
int c[maxm];
int n,q;
int lowbit(int i){
return i&-i;
}
void add(int i,int t){
while(i<=n){
c[i]+=t,i+=lowbit(i);
}
}
int ask(int i){
int ans=0;
while(i){
ans+=c[i],i-=lowbit(i);
}
return ans;
}
void solve(int l,int r,int ql,int qr){
if(ql>qr)return ;
if(l==r){
for(int i=ql;i<=qr;i++){
if(Q[i].op==2)ans[Q[i].id]=l;
}
return ;
}
int mid=(l+r)>>1;
int cnt1=0,cnt2=0;
for(int i=ql;i<=qr;i++){
if(Q[i].op==1){
if(Q[i].y<=mid)lc[++cnt1]=Q[i];//[st,mid]
else add(Q[i].x,Q[i].k),rc[++cnt2]=Q[i];//[mid+1,ed]
}else if(Q[i].op==2){
int t=ask(Q[i].y)-ask(Q[i].x-1);
if(t>=Q[i].k)rc[++cnt2]=Q[i];
else Q[i].k-=t,lc[++cnt1]=Q[i];
}
}
for(int i=ql;i<=qr;i++){//clear
if(Q[i].op==1&&Q[i].y>mid){
add(Q[i].x,-Q[i].k);
}
}
for(int i=1;i<=cnt1;i++){
Q[ql+i-1]=lc[i];
}
for(int i=1;i<=cnt2;i++){
Q[ql+cnt1+i-1]=rc[i];
}
solve(l,mid,ql,ql+cnt1-1);
solve(mid+1,r,ql+cnt1,qr);
}
signed main(){
scanf("%d%d",&n,&q);
int tot=0;
int q1=0;
for(int i=1;i<=q;i++){
char op[3];scanf("%s",op);
int x,y;scanf("%d%d",&x,&y);
if(op[0]=='C'){//修改
if(mark[x]){
Q[++tot]={1,x,mark[x],-1,666};//删掉之前的
}
Q[++tot]={1,x,y,1,666};
mark[x]=y;
}else{//查询
Q[++tot]={2,x,y,8,++q1};
}
}
solve(0,1e9,1,tot);
for(int i=1;i<=q1;i++){
printf("%d\n",ans[i]);
}
return 0;
}