zoj - 2112 带修改主席树 + 空间优化
题意:求区间第k小
思路:带修改区间第k小裸题,无修改的主席树是维护一个前缀线段树,每次更新log个节点,用root 和 ls rs作为每颗前缀线段树的根节点和左右子树的索引(相当于指针),带修改的主席树是也是维护前缀线段树,不过是用树状数组维护,思想和树状数组维护前缀和一样,每次向上更新,向下求和;时间和空间复杂度都是(n+q)*logn*logn;但是zoj卡内存,简直心里阴影,交了近100发才A。。。由于修改比较少内存优化后时间空间复杂度降低到了n*logn+q*logn*logn,但是没有太理解优化的原理,优化操作是先建一颗静态主席树,然后修改操作用另一个S数组索代替root引根节点
AC代码:
#include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a,x) memset(a,x,sizeof(a)) #define step(x) fixed<< setprecision(x)<< #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define ll long long #define endl ("\n") #define ft first #define sd second #define lrt (rt<<1) #define rrt (rt<<1|1) using namespace std; const ll mod=1e9+7; const ll INF = 1e18+1LL; const int inf = 1e9+1e8; const double PI=acos(-1.0); const int N=6e4+100; int sum[32*N],ls[32*N],rs[32*N],root[N],S[N],cnt; int n,m,sz,tk[N],a[N]; void creat(int &cur, int l, int r){ cur=++cnt; sum[cur]=0; if(l==r) return; int mid=l+r>>1; creat(ls[cur],l,mid); creat(rs[cur],mid+1, r); } void update(int &cur, int l, int r, int p, int last, int u){ cur=++cnt; ls[cur]=ls[last]; rs[cur]=rs[last]; sum[cur]=sum[last]+u; if(l==r) return; int mid=l+r>>1; if(p<=mid) update(ls[cur], l, mid, p, ls[cur], u); else update(rs[cur], mid+1, r, p, rs[cur], u); } int lowbit(int x){ return x&(-x); } void add(int x, int p, int u){ while(x<=n){ update(S[x],1,sz,p,S[x],u); x+=lowbit(x); } } int query(int l, int r, int L, int R, int k){ int bit[60010], rtl=root[L], rtr=root[R]; for(int i=L; i>0; i-=lowbit(i)) bit[i]=S[i]; for(int i=R; i>0; i-=lowbit(i)) bit[i]=S[i]; while(l<r){ int t=sum[ls[rtr]]-sum[ls[rtl]]; for(int i=R; i>0; i-=lowbit(i)) t+=sum[ls[bit[i]]]; for(int i=L; i>0; i-=lowbit(i)) t-=sum[ls[bit[i]]]; int mid=l+r>>1; if(t>=k){ for(int i=L; i>0; i-=lowbit(i)) bit[i]=ls[bit[i]]; for(int i=R; i>0; i-=lowbit(i)) bit[i]=ls[bit[i]]; rtl=ls[rtl],rtr=ls[rtr],r=mid; } else{ for(int i=L; i>0; i-=lowbit(i)) bit[i]=rs[bit[i]]; for(int i=R; i>0; i-=lowbit(i)) bit[i]=rs[bit[i]]; rtl=rs[rtl],rtr=rs[rtr],l=mid+1; k-=t; } } return l; } struct Qu{ char c[4]; int l, r, k; }q[10005]; void hash_init(){ sort(tk+1,tk+1+sz); sz=unique(tk+1,tk+1+sz)-(tk+1); } int _hash(int x){ return lower_bound(tk+1,tk+1+sz,x)-tk; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); cnt=0,sz=0;//sz表示线段树(主席树)的叶子节点数 for(int i=1; i<=n; ++i){ scanf("%d",&a[i]); tk[++sz]=a[i]; } for(int i=1; i<=m; ++i){ scanf("%s",q[i].c); if(q[i].c[0]=='Q'){ scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k); } else{ scanf("%d%d",&q[i].l,&q[i].r); tk[++sz]=q[i].r; } } hash_init(); creat(root[0],1,sz); for(int i=1; i<=n; ++i){ update(root[i],1,sz,_hash(a[i]),root[i-1],1); } for(int i=1; i<=n; ++i) S[i]=root[0]; for(int i=1; i<=m; ++i){ if(q[i].c[0]=='Q'){ printf("%d\n",tk[query(1, sz, q[i].l-1, q[i].r, q[i].k)] ); } else{ add(q[i].l, _hash(a[q[i].l]), -1); add(q[i].l, _hash(q[i].r), 1); a[q[i].l]=q[i].r; } } } return 0; }