我就算去学总体二分,CDQ分治,也不学树套树。
树套树真好用。node
我相信来看带修改主席树的应该自认为对主席树非常了解,若是还没深入理解请不要看继续看下去了,由于那样就算学了也没法深入理解。
首先咱们来分析一下主席树,它是权值线段树+离散化+再加动态开点,使空间复杂度和时间复杂度都降到了\(nlogn\)。那么若是带一个单点修改该怎么办?咱们就想到了支持单点修改,区间查询的数据结构树状数组和线段树,但因为线段树常数又大,码量又大于树状数组。因此在这里咱们用树状数组套主席树。咱们先来看一下树状数组的图。
ios
这时容易发现,只要把树状数组上的每个节点换成一颗主席树就好了,
单点修改,直接按照树状数组的修改就好了。
若是不理解的话,就想象一下树状数组的每个节点挂了一颗主席树。数组
主席树查询复杂度为\(nlogn\),树状数组时间复杂度为\(logn\),因此时间复杂度为\(n{logn}^2\)。数据结构
主席树空间复杂度为\(nlogn\),每一个节点最多存入\(logn\)个树状数组(由于每次加lowbit(i)),
因为咱们是在线开点,因此空间复杂度为\(n{logn}^2\)。
代码以下:spa
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100010],hash[101000],tot,root[201000],cnt,n,m,tt,qll[200100],qrr[20000]; int q1,q2,id[201000],b[201000]; struct TREE { int ln,rn,zhi; }t[10010000]; struct NODE { int l,r,k,flag; }q[100100]; int lowbit(int x) {return (x)&(-x);} void gai(int &node,int l,int r,int hs,int v) { if(!node) node=++tot; t[node].zhi+=v; if(l==r) return; int mid=(l+r)/2; if(hs<=mid) gai(t[node].ln,l,mid,hs,v); else gai(t[node].rn,mid+1,r,hs,v); } void add(int p,int v) { hash[p]=lower_bound(a+1,a+1+tt,hash[p])-a; //cout<<hash[p]<<endl; for(int i=p;i<=n;i+=lowbit(i)) gai(root[i],1,tt,hash[p],v); } char s[2]; int SUM() { int ans1=0,ans2=0; for(int i=1;i<=q1;i++) ans1+=t[t[qrr[i]].ln].zhi; for(int i=1;i<=q2;i++) ans2+=t[t[qll[i]].ln].zhi; return ans1-ans2; } int cha(int qr,int ql,int l,int r,int k) { q1=0,q2=0; for(int i=qr;i>=1;i-=lowbit(i)) qrr[++q1]=root[i]; for(int i=ql;i>=1;i-=lowbit(i)) qll[++q2]=root[i]; while(l<r) { int lsiz=SUM(),mid=(l+r)/2; if(k<=lsiz) { for(int i=1;i<=q1;i++) qrr[i]=t[qrr[i]].ln; for(int i=1;i<=q2;i++) qll[i]=t[qll[i]].ln; r=mid; } else { for(int i=1;i<=q1;i++) qrr[i]=t[qrr[i]].rn; for(int i=1;i<=q2;i++) qll[i]=t[qll[i]].rn; l=mid+1;k-=lsiz; } } return l; } int main() { int x,y,z; cin>>n>>m; for(int i=1;i<=n;i++) { scanf("%d",&a[i]);b[i]=a[i]; hash[++cnt]=a[i]; } for(int i=1;i<=m;i++) { scanf("%s",s); if(s[0]=='Q') scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k),q[i].flag=1; else { scanf("%d%d",&q[i].l,&q[i].r); a[++cnt]=q[i].r;hash[cnt]=a[cnt]; } } sort(a+1,a+1+cnt); tt=unique(a+1,a+1+cnt)-a-1; for(int i=1;i<=n;i++) add(i,1); for(int i=1;i<=m;i++) { if(q[i].flag==1) printf("%d\n",a[cha(q[i].r,q[i].l-1,1,tt,q[i].k)]); else { hash[q[i].l]=b[q[i].l]; add(q[i].l,-1); hash[q[i].l]=q[i].r; b[q[i].l]=q[i].r; add(q[i].l,1); } } }