第一道自己脑补出来的整体二分,这样我就不用去打那个树桩数组套主席树了
开心
主要是把各个操作分开
op==1 则为加操作
op==2 则为减操作
op==3则为区间查询操作
之后直接将询问的次数和值域二分求解即可
#include<bits/stdc++.h> #define lowbit(x) x&(-x) using namespace std; const int N=1e5+7; const int INF=1e9+7; int m,n,T; int ans[N],num[N]; struct node { int x,y,id,op; int k; } q[N],q1[N],q2[N]; struct Tree { int tree[N<<2]; void add(int x,int val) { for (;x<=n;x+=lowbit(x)) tree[x]+=val; } int query(int x) { int ans=0; for (;x;x-=lowbit(x)) ans+=tree[x]; return ans; } } G; int cur[N]; void solve(int from,int to,int l,int r) { if (from>to||l>r) return; if (l==r) { for (int i=from;i<=to;i++) if (q[i].op==3) ans[q[i].id]=l; return; } int mid=(l+r)>>1; for (int i=from;i<=to;i++) { if (q[i].k<=mid) { if (q[i].op==2) G.add(q[i].x,-1); if (q[i].op==1) G.add(q[i].x,1); } if (q[i].op==3) cur[i]=G.query(q[i].y)-G.query(q[i].x-1); } for (int i=from;i<=to;i++) if (q[i].k<=mid) { if (q[i].op==2) G.add(q[i].x,1); if (q[i].op==1) G.add(q[i].x,-1); } int t1=0,t2=0; for (int i=from;i<=to;i++) if (q[i].op==1||q[i].op==2) { if (q[i].k<=mid) q1[t1++]=q[i]; else q2[t2++]=q[i]; } else { if (cur[i]>=q[i].k) q1[t1++]=q[i]; else q[i].k-=cur[i],q2[t2++]=q[i]; } for (int i=0;i<t1;i++) q[from+i]=q1[i]; for (int i=0;i<t2;i++) q[from+t1+i]=q2[i]; solve(from,from+t1-1,l,mid); solve(from+t1,to,mid+1,r); } int main() { freopen("dynrank.in","r",stdin); freopen("dynrank.out","w",stdout); scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { int x;scanf("%d",&x); q[i].op=1;q[i].x=i;q[i].k=x;num[i]=x; } int tot=0; for (int i=1;i<=m;i++) { char s[5];int x,y,k; scanf("%s",s);scanf("%d%d",&x,&y); if (s[0]=='Q') {scanf("%d",&k);q[++n].op=3;q[n].x=x;q[n].y=y;q[n].id=++tot;q[n].k=k;} if (s[0]=='C') { q[++n].op=2;q[n].x=x;q[n].k=num[x]; q[++n].op=1;q[n].x=x;q[n].k=y;num[x]=y; } } solve(1,n,0,INF); for (int i=1;i<=tot;i++) printf("%d ",ans[i]); } return 0; }