写挂了好多次,也不太理解
带修改的情况如果还用(权值线段树)主席树,每个点(root[i])维护前缀的某值出现次数,
每次修改需要对此点后面所有主席树修改,共$nlogn$个
这里用树状数组维护前缀和,平时的树状数组实际上每个点维护的是原序列$[i,i-lowbit(i)+1]$这些值,这里也让每个树状数组维护这样一个区间的信息,而不是前缀的,这样修改一个点的值只会影响$logn$棵主席树,查询也是$logn$棵主席树的信息加起来就是整个区间的信息,每次修改存下所有需要修改/查询的主席树,同步进行加减/向下跳,这样每次修改的复杂度就是$log^2 n$的
主席树真的好慢...跑了12s,动态区间第k大还有整体二分等做法
(我竟然连树状数组都不理解...还看了好久树状数组)
#include<bits/stdc++.h> #define mid (l+r>>1) #define lbt(x) (x&-x) using namespace std; const int maxn=100009; inline int read(){ int ret=0,fix=1;char ch; while(!isdigit(ch=getchar()))fix=ch=='-'?-1:fix; do ret=(ret<<1)+(ret<<3)+ch-'0'; while(isdigit(ch=getchar())); return fix*ret; } struct qqq{ int tp,l,r,x; }qu[maxn]; int n,m,tot,cnt; int hsh[maxn<<1],a[maxn]; struct node{ int l,r,cnt; }t[maxn*250]; int root[maxn],q[2][30]; inline void insert(int &x,int l,int r,int pos,int val){ if(!x)x=++tot; t[x].cnt+=val; if(l==r)return ; if(pos<=mid)insert(t[x].l,l,mid,pos,val); else insert(t[x].r,mid+1,r,pos,val); } inline void add(int pos,int val,int d){ while(pos<=n){ insert(root[pos],1,cnt,val,d); pos+=lbt(pos); } } inline int queryt(int l,int r,int k){ if(l==r)return l; int ans=0; for(int i=1;i<=q[0][0];i++)ans-=t[t[q[0][i]].l].cnt; for(int i=1;i<=q[1][0];i++)ans+=t[t[q[1][i]].l].cnt; if(ans>=k){ for(int i=1;i<=q[0][0];i++)q[0][i]=t[q[0][i]].l; for(int i=1;i<=q[1][0];i++)q[1][i]=t[q[1][i]].l; return queryt(l,mid,k); } else{ for(int i=1;i<=q[0][0];i++)q[0][i]=t[q[0][i]].r; for(int i=1;i<=q[1][0];i++)q[1][i]=t[q[1][i]].r; return queryt(mid+1,r,k-ans); } } inline int query(int l,int r,int k){ l--; q[0][0]=q[1][0]=0; while(l){ q[0][++q[0][0]]=root[l]; l-=lbt(l); } while(r){ q[1][++q[1][0]]=root[r]; r-=lbt(r); } return queryt(1,cnt,k); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)a[i]=read(),hsh[++cnt]=a[i]; char op; for(int i=1;i<=m;i++){ op=getchar(); while(op!='C' &&op!='Q')op=getchar(); if(op=='Q'){ qu[i].l=read(),qu[i].r=read(),qu[i].x=read(); } else if(op=='C'){ qu[i].tp=1; qu[i].l=read(),qu[i].x=read(); hsh[++cnt]=qu[i].x; } } sort(hsh+1,hsh+1+cnt); cnt=unique(hsh+1,hsh+1+cnt)-hsh-1; for(int i=1;i<=n;i++)a[i]=lower_bound(hsh+1,hsh+1+cnt,a[i])-hsh; for(int i=1;i<=m;i++) if(qu[i].tp)qu[i].x=lower_bound(hsh+1,hsh+1+cnt,qu[i].x)-hsh; for(int i=1;i<=n;i++)add(i,a[i],1);//建树 for(int i=1;i<=m;i++){ if(qu[i].tp){ add(qu[i].l,a[qu[i].l],-1); add(qu[i].l,qu[i].x,1); a[qu[i].l]=qu[i].x; } else{ printf("%d ",hsh[query(qu[i].l,qu[i].r,qu[i].x)]); } } }