ZOJ 2112 Dynamic Rankings(二分,树套树)

动态区间询问kth,单点修改。

区间用线段树分解,线段树上每条线段存一颗平衡树。

不能直接得到kth,但是利用val和比val小的个数之间的单调性,二分值。log^3N。

修改则是一次logN*logN。

总体是Nlog^2N+Mlog^3N。

一个值可以对应多个名次。每次查询严格小于val的个数。

把之前的Treap的值域加了一个vs表示值的出现次数,这样就可以支持重复的val了,并可以统计出值出现次数。

这样每个值的名次就变成一个区间了。

复杂度更低的做法:树状数组套主席树,还不太会。

#include<bits/stdc++.h>
using namespace std;

#define PS push
const int maxn = 5e4+5;
const int LgN = 17, maxnds = maxn*LgN;


namespace Treap
{
    int r[maxnds],s[maxnds],v[maxnds],ch[maxnds][2],vs[maxnds];
    const int nil = 0, chsz = sizeof(ch[0]);
    #define CLRch(x) memset(ch[x],0,chsz);
    stack<int> meos;
    void Treap_init(){
        for(int i = maxnds; --i;  ){
            meos.PS(i);
        }
        s[nil] = 0;
    }

    inline int newNode(int val){
        int i = meos.top(); meos.pop();
        r[i] = rand(); v[i] = val;
        vs[i] = s[i] = 1; CLRch(i)
        return i;
    }

    inline void delt(int i) { meos.PS(i); }

    #define lch ch[o][0]
    #define rch ch[o][1]

    inline void mt(int o){
        s[o] = s[lch] + s[rch] + vs[o];
    }
    inline int cmp(int a,int b){
        return a == b?-1:(a>b?0:1);
    }

    inline void rot(int &o,int d){
        int k = ch[o][d^1];
        ch[o][d^1] = ch[k][d];
        ch[k][d] = o;
        mt(o); mt(k);
        o = k;
    }

    int qval;
    void inst(int &o){
        if(!o){
            o = newNode(qval);
        }else {
            int d = cmp(v[o],qval);
            if(!~d) {
                s[o]++; vs[o]++; return;
            }
            inst(ch[o][d]);
            if(r[ch[o][d]] > r[o]) rot(o,d^1);
            else mt(o);
        }
    }



    void rmov(int &o){
        int d = cmp(v[o],qval);
        if(!~d){
            if(vs[o] > 1) {
               s[o]--; vs[o]--; return;
            }
            if(!lch){
                delt(o);
                o = rch;
            }else if(!rch){
                delt(o);
                o =  lch;
            }else {
                int d2 = r[lch] > r[rch] ? 1 : 0;
                rot(o,d2);
                rmov(ch[o][d2]);
            }
        }else{
            rmov(ch[o][d]);
        }
        if(o) mt(o);
    }

    void clrTree(int &o){
        if(lch) clrTree(lch);
        if(rch) clrTree(rch);
        delt(o);
        o = nil;
    }
    int Finded;
    int Order(int &o){
        if(!o) return 0;
        int d = cmp(v[o],qval);
        if(!~d){
            Finded += vs[o];
            return s[lch];
        }else{
            return  (d?s[lch]+vs[o]:0) + Order(ch[o][d]);
        }
    }
}

using namespace Treap;


int rt[maxn<<2];

int a[maxn];
int n;

#define para int o = 1, int l = 1,int r = n
#define lo (o<<1)
#define ro (o<<1|1)
#define TEMP int mid = (l+r)>>1;
#define lsn lo, l, mid
#define rsn ro, mid+1, r
#define insd ql<=l&&r<=qr
int ql,qr,val;

void build(para)
{
    if(rt[o]) clrTree(rt[o]);
    for(int i = l; i <= r; i++){
        qval = a[i]; inst(rt[o]);
    }
    if(l == r) return;
    else {
        TEMP
        build(lsn);
        build(rsn);
    }
}

int query(para)
{
    if(insd){
        return Order(rt[o]);
    }else {
        TEMP
        int re = 0;
        if(ql<=mid) re += query(lsn);
        if(qr>mid) re += query(rsn);
        return re;
    }
}

int qpos;
void Change(para)
{
    qval = a[qpos];
    rmov(rt[o]);
    qval = val;
    inst(rt[o]);
    if(l < r){
        TEMP
        if(qpos <= mid) Change(lsn);
        else Change(rsn);
    }
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("data.txt","r",stdin);
#endif
    int T; scanf("%d",&T);
    Treap_init();
    while(T--){
        int m; scanf("%d%d",&n,&m);
        int low = 1e9, high = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d",a+i);
            low = min(a[i],low);
            high = max(a[i],high);
        }
        build();
        while(m--){
            char op[2];
            int x,y;
            scanf("%s%d%d",op,&x,&y);
            if(*op == 'Q'){
                ql = x; qr = y;
                int k; scanf("%d",&k);
                int L = low,R = high;
                while(L<R){
                    int M = (L+R+1)>>1;
                    qval = M;
                    Finded = 0;
                    int re = query();
                    if(k <= re) R = M-1;
                    else if(k > re+Finded) L = M+1;
                    else { L = M; break; }
                }
                printf("%d\n",L);
            }else {
               qpos = x;
               val = y;
               Change();
               a[qpos] = y;
               low = min(y,low);
               high = max(y,high);
            }
        }
    }
    return 0;
}

 

posted @ 2015-10-09 23:24  陈瑞宇  阅读(259)  评论(0编辑  收藏  举报