带修改的主席树,其实这种,已经不能算作主席树了,因为这个没有维护可持久化的。。。
主席树直接带修改的话,由于这种数据结构是可持久化的,那么要相应改动,这个节点以后所有的主席树,这样单次修改,就达到n*log n 的复杂度
现在介绍这种待修改的主席树,本质上是用树状数组的区间查询维护的线段树,树状数组的每个点,都开一个权值线段树,维护的是lowbit(x)-x之间的数字的出现次数
这样我们相当于,把一个1-n权值线段树,用树状数组给砍成logn段,这样就非常方便。。。我们用树状数组遍历维护前缀和的过程,变成维护树的前缀的过程,这样单次维护的复杂度,大概为两个log,还是可以接受的
模版题
#include<bits/stdc++.h> using namespace std; const int maxx = 2e5+6; struct node{ int l,r,cnt; }tree[maxx*500]; struct query{ int l,r,k; }que[maxx*2]; int trl[maxx],trr[maxx],a[maxx],root[maxx]; int cnt,lenx,leny,n,sz; vector<int>p; void update(int l,int r,int pre,int &now,int pos,int w){ now=++cnt; tree[now]=tree[pre]; tree[now].cnt+=w; if (l==r) return ; int mid=(l+r)>>1; if (pos<=mid){ update(l,mid,tree[pre].l,tree[now].l,pos,w); }else{ update(mid+1,r,tree[pre].r,tree[now].r,pos,w); } } /**查询区间第k大**/ int query(int l,int r,int k){ if(l==r) return l; int s=0; ///查询区间个数 for (int i=1;i<=lenx;i++){ s-=tree[tree[trl[i]].l].cnt; } for (int i=1;i<=leny;i++){ s+=tree[tree[trr[i]].l].cnt; } int mid=(l+r)>>1; if(k<=s){ ///把询问变成询问单点的左子树 for(int i=1;i<=lenx;i++){ trl[i]=tree[trl[i]].l; } for(int i=1;i<=leny;i++){ trr[i]=tree[trr[i]].l; } return query(l,mid,k); }else { ///把询问变成询问单点的右子树 for(int i=1;i<=lenx;i++){ trl[i]=tree[trl[i]].r; } for(int i=1;i<=leny;i++){ trr[i]=tree[trr[i]].r; } return query(mid+1,r,k-s); } } int lowbit(int x){ return x&(-x); } void add(int x,int w){ int pos=lower_bound(p.begin(),p.end(),a[x])-p.begin()+1; for (int i=x;i<=n;i+=lowbit(i)){ update(1,sz,root[i],root[i],pos,w); } } int main(){ int q; scanf("%d%d",&n,&q); cnt=0; for (int i=1;i<=n;i++){ scanf("%d",&a[i]); p.push_back(a[i]); } for (int i=1;i<=q;i++){ char op[3]; scanf("%s",op); if(op[0]=='C'){ scanf("%d%d",&que[i].l,&que[i].r); que[i].k=0; p.push_back(que[i].r); }else{ scanf("%d%d%d",&que[i].l,&que[i].r,&que[i].k); } } ///把点全部离散排序 sort(p.begin(),p.end()); p.erase(unique(p.begin(),p.end()),p.end()); sz=p.size(); for (int i=1;i<=n;i++){ add(i,1); } for (int i=1;i<=q;i++){ if (que[i].k){ lenx=0;leny=0; for (int j=que[i].r;j;j-=lowbit(j)){ trr[++leny]=root[j]; } for (int j=que[i].l-1;j;j-=lowbit(j)){ trl[++lenx]=root[j]; } printf("%d ",p[query(1,sz,que[i].k)-1]); }else{ ///前缀中删除这个树的影响 add(que[i].l,-1); a[que[i].l]=que[i].r; add(que[i].l,1); } } return 0; }