• 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
    ",L);
                }else {
                   qpos = x;
                   val = y;
                   Change();
                   a[qpos] = y;
                   low = min(y,low);
                   high = max(y,high);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    C# 线程手册 第二章 .NET 中的线程系列
    C# 线程手册 第四章 线程设计原则
    C# 线程手册 第四章 线程设计原则 MTA 线程模型
    C# 线程手册 第三章 使用线程 创建线程安全的包装器(实战篇)
    C# 线程手册 第一章 线程定义系列
    C# 线程手册 第三章 使用线程 小心死锁
    C# 线程手册 第四章 线程设计原则 线程及线程间关系
    C# 线程手册 第一章 线程定义 中断和局部线程存储
    C# 线程手册 第三章 使用线程 实现一个数据库连接池(实战篇)
    C# 线程手册 第四章 线程设计原则 对等线程模型
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4865484.html
Copyright © 2020-2023  润新知