树状数组套主席树有点难懂qwq 不好理解
树状数组套主席树的直观理解应该是:树状数组的每一个节点是一棵主席树。
普通区间修改我们是创建1个线段树,树状数组套主席树的时候我们就创建log个线段树。
普通区间查询我们是把from-1 和to 两个线段树作差,树状数组套主席树的时候我们就把from-1的前缀和的log个线段树和to的log个线段树作差。
比较玄学qwq 我好像现在还是没懂
放上代码吧
#include<cctype> #include<cstring> #include<cstdlib> #include<algorithm> #include<cstdio> #define mid ((l+r)>>1) #define maxn 10005 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch==‘-‘) f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-‘0‘; ch=getchar(); } return num*f; } inline int low(int i){ return i&(-i); } int s[maxn*2],q[maxn*2]; int rt[maxn*20*20]; int sum[maxn*20*20]; int ls[maxn*20*20]; int rs[maxn*20*20]; int d[maxn],w[maxn],tot,n,m,size,point,totd,totw; void build(int &o,int l,int r){ o=++tot; if(l==r) return; build(ls[o],l,mid); build(rs[o],mid+1,r); } void update(int &o,int l,int r,int last,int p,int val){ o=++tot; ls[o]=ls[last]; rs[o]=rs[last]; sum[o]=sum[last]+val; if(l==r) return; if(p<=mid) update(ls[o],l,mid,ls[last],p,val); else update(rs[o],mid+1,r,rs[last],p,val); } void add(int from,int val){ int value=q[from]; while(from<=n){ update(rt[from],1,size,rt[from],value,val); from+=low(from); } } int query(int l,int r,int e){ if(l==r) return l; int cnt=0; for(int i=1;i<=totw;++i) cnt+=sum[ls[w[i]]]; for(int i=1;i<=totd;++i) cnt-=sum[ls[d[i]]]; if(e<=cnt){ for(int i=1;i<=totd;++i) d[i]=ls[d[i]]; for(int i=1;i<=totw;++i) w[i]=ls[w[i]]; return query(l,mid,e); } else{ for(int i=1;i<=totd;++i) d[i]=rs[d[i]]; for(int i=1;i<=totw;++i) w[i]=rs[w[i]]; return query(mid+1,r,e-cnt); } } struct Que{ bool f; int from,to,rank; void add(int opt,int x,int y,int z){ f=opt;from=x;to=y;rank=z; } }que[maxn]; int main(){ n=read(),m=read(); for(int i=1;i<=n;++i) s[++point]=q[i]=read(); for(int i=1;i<=m;++i){ char ch[10];int x,y; scanf("%s%d%d",ch,&x,&y); if(ch[0]==‘Q‘){ int z=read(); que[i].add(0,x,y,z); } else{ que[i].add(1,x,y,0); s[++point]=y; } } sort(s+1,s+point+1); size=unique(s+1,s+point+1)-s-1; for(int i=1;i<=n;++i) q[i]=lower_bound(s+1,s+size+1,q[i])-s; for(int i=1;i<=m;++i) if(que[i].f) que[i].to=lower_bound(s+1,s+size+1,que[i].to)-s; //build(rt[0],1,size); for(int i=1;i<=n;++i) add(i,1); for(int i=1;i<=m;++i){ bool f=que[i].f;int from=que[i].from,to=que[i].to,rank=que[i].rank; if(f){ add(from,-1); q[from]=to; add(from,1); } else{ totd=totw=0; for(int j=from-1;j;j-=low(j)) d[++totd]=rt[j]; for(int j=to;j;j-=low(j)) w[++totw]=rt[j]; printf("%d\n",s[query(1,size,rank)]); } } return 0; }