題目大意:維護帶修改區間 K 小值。node
題解:學習到了樹狀數組套權值線段樹。 主席樹,即:可持久化權值線段樹,支持維護靜態區間的 K 小值問題,其核心思想是維護 N 棵權值線段樹,每一個線段樹維護的是序列 [1,i] 的權值,並根據可持久化思想使得空間複雜度維持在 $O(nlogn)$。 樹狀數組套權值線段樹,支持維護帶修改區間 K 小值的問題,其核心思想是改變靜態主席樹中各個權值線段樹的前綴和處理方式,在這裏採用樹狀數組中的前綴和處理方式,平衡了修改和查詢的時間和空間。時間和空間複雜度爲 $O(nlognlogn)$。注意:這裏 log 是以 2 爲底的對數。1e5 的 log2 大約爲16,所以內存開 300 倍。c++
代碼以下git
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch)); do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch)); return f*x; } char opt[5]; int n,m,a[maxn],tmp[2][20],cnt[2]; int d[maxn<<1],len; struct operation{bool tag;int l,r,k;int pos,val;}q[maxn]; struct node{ #define ls(x) t[x].lc #define rs(x) t[x].rc int lc,rc,sum; }t[maxn*300]; int tot,root[maxn]; inline void pushup(int o){t[o].sum=t[ls(o)].sum+t[rs(o)].sum;} void insert(int &o,int l,int r,int pos,int val){ if(!o)o=++tot; if(l==r){t[o].sum+=val;return;} int mid=l+r>>1; if(pos<=mid)insert(ls(o),l,mid,pos,val); else insert(rs(o),mid+1,r,pos,val); pushup(o); } int query(int l,int r,int k){ if(l==r)return l; int mid=l+r>>1; int lsize=0; for(int i=1;i<=cnt[1];i++)lsize+=t[ls(tmp[1][i])].sum; for(int i=1;i<=cnt[0];i++)lsize-=t[ls(tmp[0][i])].sum; if(k<=lsize){ for(int i=1;i<=cnt[1];i++)tmp[1][i]=ls(tmp[1][i]); for(int i=1;i<=cnt[0];i++)tmp[0][i]=ls(tmp[0][i]); return query(l,mid,k); }else{ for(int i=1;i<=cnt[1];i++)tmp[1][i]=rs(tmp[1][i]); for(int i=1;i<=cnt[0];i++)tmp[0][i]=rs(tmp[0][i]); return query(mid+1,r,k-lsize); } } inline int lowbit(int x){return x&-x;} inline void add(int x,int val){ int pos=lower_bound(d+1,d+len+1,a[x])-d; for(int i=x;i<=n;i+=lowbit(i))insert(root[i],1,len,pos,val); } int querykth(int l,int r,int k){ memset(tmp,0,sizeof(tmp)),cnt[1]=cnt[0]=0; for(int i=r;i;i-=lowbit(i))tmp[1][++cnt[1]]=root[i]; for(int i=l-1;i;i-=lowbit(i))tmp[0][++cnt[0]]=root[i]; return query(1,len,k); } void read_and_parse(){ n=read(),m=read(); for(int i=1;i<=n;i++)d[++len]=a[i]=read(); for(int i=1;i<=m;i++){ scanf("%s",opt); if(opt[0]=='Q')q[i].tag=0,q[i].l=read(),q[i].r=read(),q[i].k=read(); else q[i].tag=1,q[i].pos=read(),d[++len]=q[i].val=read(); } sort(d+1,d+len+1); len=unique(d+1,d+len+1)-d-1; for(int i=1;i<=n;i++)add(i,1); } void solve(){ for(int i=1;i<=m;i++){ if(q[i].tag){ add(q[i].pos,-1); a[q[i].pos]=q[i].val; add(q[i].pos,1); }else{ printf("%d\n",d[querykth(q[i].l,q[i].r,q[i].k)]); } } } int main(){ read_and_parse(); solve(); return 0; }