和大奕哥一起学习了主席树,机房里杰哥看了之后一直说可以优化空间,题解写的太low了,所以我今天写了一个动态开点的线段树来优化一波空间,bz上试了一下,确实比网上看的题解省空间。
网上的题解是每一次都新开点,是可持久化的写法,我写的是正经的线段树动态开点。
——by VANE
附上代码
#include<bits/stdc++.h> using namespace std; const int N=10010,INF=1e9+10; int n,m,pl,tl,mx; int a[N<<1],num[N<<1],crt[N<<1]; char s[10]; struct tnode { int lc,rc,cnt; }t[N*120]; struct ques { int l,r,k,x,d; bool tmp; }q[N]; struct node { int d,id; }p[N<<1]; bool cmp(node x,node y) {return x.d<y.d;} void merge(int x) { t[x].cnt=t[t[x].lc].cnt+t[t[x].rc].cnt; } void update(int &rt,int p,int d,int l,int r) { if(!rt) rt=++tl; if(l==r) { t[rt].cnt+=d; return; } int mid=l+r>>1; if(p<=mid) update(t[rt].lc,p,d,l,mid); else update(t[rt].rc,p,d,mid+1,r); merge(rt); } void add(int x,int p,int d) { for(int i=x;i<=n;i+=i&-i) update(i,p,d,1,mx); } int getsum(int x) { int ans=0; for(int i=x;i;i-=i&-i) ans+=t[t[crt[i]].lc].cnt; return ans; } int query(int lx,int rx,int k) { for(int i=lx-1;i>=1;i-=(i&(-i))) crt[i]=i; for(int i=rx;i>=1;i-=(i&(-i))) crt[i]=i; int l=1,r=mx,mid,sum; while(l<r) { mid=(l+r)/2; sum=getsum(rx)-getsum(lx-1); if(sum>=k) { r=mid; for(int i=lx-1;i>=1;i-=(i&(-i))) crt[i]=t[crt[i]].lc; for(int i=rx;i>=1;i-=(i&(-i))) crt[i]=t[crt[i]].lc; } else { l=mid+1; k-=sum; for(int i=lx-1;i>=1;i-=(i&(-i))) crt[i]=t[crt[i]].rc; for(int i=rx;i>=1;i-=(i&(-i))) crt[i]=t[crt[i]].rc; } } return l; } int main() { scanf("%d%d",&n,&m); pl=n;tl=n; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); p[i].d=a[i];p[i].id=i; } for(int i=1;i<=m;i++) { scanf("%s",s); if(s[0]=='Q') { q[i].tmp=0; scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k); } else { q[i].tmp=1; scanf("%d%d",&q[i].x,&q[i].d); p[++pl].d=q[i].d;p[pl].id=n+i; } } sort(p+1,p+1+pl,cmp); mx=0;p[0].d=INF; for(int i=1;i<=pl;i++) { if(p[i].d!=p[i-1].d) mx++,num[mx]=p[i].d; if(p[i].id<=n) a[p[i].id]=mx; else q[p[i].id-n].d=mx; } for(int i=1;i<=n;i++) add(i,a[i],1); for(int i=1;i<=m;i++) { if(q[i].tmp==0) printf("%d ",num[query(q[i].l,q[i].r,q[i].k)]); else { add(q[i].x,a[q[i].x],-1); add(q[i].x,q[i].d,1); a[q[i].x]=q[i].d; } } return 0; }