动态第K大 (树状数组套主席树)
在静态主席树的基础上,外面套一层树状数组
主席树就是利用前缀和的性质
利用树状数组维护前缀和的功能,可以做到 log^2 的复杂度进行单点修改
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<stack> #include<queue> using namespace std; typedef long long ll; const int maxn = 100010; int n,m,q; int a[maxn],b[maxn*2],qa[maxn],qb[maxn],qc[maxn]; int rt[maxn*600],lc[maxn*600],rc[maxn*600],sz[maxn*600],tot; int xx[maxn],yy[maxn],totx,toty; char op[10]; void modify(int &i,int o,int l,int r,int p,int k){ i=++tot; lc[i]=lc[o],rc[i]=rc[o],sz[i]=sz[o]+k; if(l==r) return; int mid=(l+r)/2; if(p<=mid) modify(lc[i],lc[i],l,mid,p,k); else modify(rc[i],rc[i],mid+1,r,p,k); } void add(int x,int k){ int p=lower_bound(b+1,b+1+q,a[x])-b; for(int i=x;i<=n;i+=i&(-i)){ modify(rt[i],rt[i],1,q,p,k); } } int query(int l,int r,int k){ if(l==r) return l; int sum=0; for(int i=1;i<=toty;i++) sum+=sz[lc[yy[i]]]; for(int i=1;i<=totx;i++) sum-=sz[lc[xx[i]]]; int mid=(l+r)/2; if(sum>=k){ for(int i=1;i<=totx;i++) xx[i]=lc[xx[i]]; for(int i=1;i<=toty;i++) yy[i]=lc[yy[i]]; return query(l,mid,k); }else{ for(int i=1;i<=totx;i++) xx[i]=rc[xx[i]]; for(int i=1;i<=toty;i++) yy[i]=rc[yy[i]]; return query(mid+1,r,k-sum); } } ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(),b[++q]=a[i]; for(int i=1;i<=m;i++){ scanf("%s",op); qa[i]=read(),qb[i]=read(); if(op[0]=='Q') qc[i]=read(); else b[++q]=qb[i]; } sort(b+1,b+1+q); q=unique(b+1,b+1+q)-b-1; for(int i=1;i<=n;i++) add(i,1); for(int i=1;i<=m;i++){ if(qc[i]){ totx=toty=0; for(int j=qa[i]-1;j>0;j-=j&(-j)) xx[++totx]=rt[j]; for(int j=qb[i];j>0;j-=j&(-j)) yy[++toty]=rt[j]; int ans=query(1,q,qc[i]); printf("%d\n",b[ans]); }else{ add(qa[i],-1); a[qa[i]]=qb[i]; add(qa[i],1); } } return 0; }