zoj - 2112 带修改主席树 + 空间优化

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;
}

 

posted on 2017-09-19 19:25  lazzzy  阅读(226)  评论(0编辑  收藏  举报

导航