zoukankan      html  css  js  c++  java
  • poj 2104 K-th Number 划分树

    划分树是在建树的过程中保存快速排序。

    划分树
    同样以1 5 2 6 3 7为例:
    根据中位数mid,将区间划分成左子树中的数小于等于mid,右子树中的数大于等于mid,得到这样一棵划分树:
            [1 5 2 6 3 7]
         [1 2 3]      [5 6 7]
       [1 2]  [3]    [5 6] [7]
      [1] [2]        [5] [6] 
    注意要保持下标的先后顺序不变
    对每一个区间,用sum[i]记录区间的左端点left到i有几个进入了左子树,即有几个数小于等于mid
    用对应的下标区间建线段树:(这里下标区间对应的是排序后的数列)
                [1 6]
         [1 3]      [4 6]
      [1 2] [3]   [4 5][6]
      [1][2]      [4][5]
    每次查找[l r]区间的第k大数时,先查看当前区间[left right]下的sum[r] - sum[l - 1]是否小于等于k,如果是,则递归到左子树,并继续在[left + sum[l - 1], left + sum[r] - 1]中找第k大数;
    否则,进入右子树,继续在[mid + l - left + 1 - sum[l - 1], mid + r - left + 1 - sum[r]]找第k - sum[r] + sum[l - 1]大数
    这样一次查询只要logn的复杂度

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define ls (rt<<1)
    #define rs ((rt<<1)|1)
    #define mid ((t[rt].l+t[rt].r)>>1)
    const int maxn = 100010;
    struct node {
        int l , r;
    }t[maxn<<2];
    int sa[maxn],num[20][maxn],cnt[20][maxn];  //sa中是排序后的,num记录每一层的排序结果,cnt[deep][i]表示第deep层,前i个数中有多少个进入左子树  
    int n , q;
    void build(int l,int r,int rt,int deep) {
        t[rt].l = l; t[rt].r = r;
        if(l == r) return;
        int mid_val = sa[mid],lsum=mid-l+1;
        for(int i=l;i<=r;i++)
            if(num[deep][i] < mid_val)
                lsum --; //lsum表示左子树中还需要多少个中值  
        int L = l , R = mid + 1;
        for(int i=l;i<=r;i++) {
            if(i == l) cnt[deep][i] = 0;
            else cnt[deep][i] = cnt[deep][i-1];
            if(num[deep][i]<mid_val || num[deep][i]==mid_val && lsum>0) {
                num[deep+1][L++] = num[deep][i];
                cnt[deep][i] ++;
                if(num[deep][i] == mid_val)
                    lsum --;
            }
            else num[deep+1][R++] = num[deep][i];
        }
        build(l,mid,ls,deep+1);
        build(mid+1,r,rs,deep+1);
    }
    int query(int l,int r,int rt,int k,int deep) {
        if(l == r) return num[deep][l];
        int s1 , s2; //s1为[tree[step].left,l-1]中分到左子树的个数  
        if(t[rt].l == l) s1 = 0;
        else s1 = cnt[deep][l-1];
        s2 = cnt[deep][r] - s1; //s2为[l,r]中分到左子树的个数  
        if(k <= s2) //左子树的数量大于k,递归左子树 
            return query(t[rt].l+s1,t[rt].l+s1+s2-1,ls,k,deep+1);
        int b1 = l-1-t[rt].l+1-s1; //b1为[tree[step].left,l-1]中分到右子树的个数  
        int b2 = r-l+1-s2; //b2为[l,r]中分到右子树的个数 
        return query(mid+1+b1,mid+1+b1+b2-1,rs,k-s2,deep+1);
    }
    int main() {
        while(~scanf("%d%d",&n,&q)) {
            for(int i=1;i<=n;i++) {
                scanf("%d",&num[1][i]);
                sa[i] = num[1][i];
            }
            sort(sa+1 , sa+n+1);
            build(1,n,1,1);
            int l , r , k;
            while(q--) {
                scanf("%d%d%d",&l,&r,&k);
                printf("%d
    " , query(l,r,1,k,1));
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    linux下shell显示-bash-4.1#不显示路径解决方法
    update chnroute
    An error "Host key verification failed" when you connect to other computer by OSX SSH
    使用dig查询dns解析
    DNS被污染后
    TunnelBroker for EdgeRouter 后记
    mdadm详细使用手册
    关于尼康黄的原因
    Panda3d code in github
    Python实例浅谈之三Python与C/C++相互调用
  • 原文地址:https://www.cnblogs.com/tobec/p/3235837.html
Copyright © 2011-2022 走看看