zoukankan      html  css  js  c++  java
  • poj 2104 K-th Number 归并树

    归并树是在建树的过程中保存归并排序。

    归并树
    以1 5 2 6 3 7为例:
    把归并排序递归过程记录下来即是一棵归并树:
            [1 2 3 5 6 7]
        [1 2 5]      [3 6 7]
       [1 5] [2]    [6 3] [7] 
      [1][5]        [6][3]
    用对应的下标区间建线段树:(这里下标区间对应的是原数列)
                [1 6]
         [1 3]      [4 6]
      [1 2] [3]   [4 5][6]
      [1][2]      [4][5]
    每次查找[l r]区间的第k大数时,在[1 2 3 4 5 6 7]这个有序的序列中二分所要找的数x,然后对应到线段树中去找[l r]中比x小的数有几个,即x的rank。由于线段树中任意区间对应到归并树中是有序的,所以在线段树中的某个区间查找比x小的数的个数也可以用二分在对应的归并树中找。这样一次查询的时间复杂度是log(n)^2。
    要注意的是,多个x有相同的rank时,应该取最大的一个。

    #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 = 100500;
    struct node {
        int l , r;
    }t[maxn<<2];
    int num[maxn] , mer[20][maxn];
    int n , q;
    void build(int l,int r,int rt,int deep) {
        t[rt].l = l; t[rt].r = r;
        if(l == r) {
            mer[deep][l] = num[l];
            return;
        }
        build(l,mid,ls,deep+1);
        build(mid+1,r,rs,deep+1);
        int i=l ,j=mid+1 , p = l;
        /**
        while(p <= r) {
            if(i > mid || mer[deep+1][i] > mer[deep+1][j])
                mer[deep][p++] = mer[deep+1][j++];
            else
                mer[deep][p++] = mer[deep+1][i++];
        }
        **/
        while(i <= mid && j <= r) {
            if(mer[deep+1][i] < mer[deep+1][j]) mer[deep][p++] = mer[deep+1][i++];
            else mer[deep][p++] = mer[deep+1][j++];
        }
        while(i <= mid) mer[deep][p++] = mer[deep+1][i++];
        while(j <= r) mer[deep][p++] = mer[deep+1][j++];
    }
    int query(int l,int r,int rt,int deep,int key) {
        if(t[rt].r < l || t[rt].l > r) return 0;
        if(t[rt].l >= l && t[rt].r <= r)
            return lower_bound(&mer[deep][t[rt].l],&mer[deep][t[rt].r]+1,key) - &mer[deep][t[rt].l];
        return query(l,r,ls,deep+1,key) + query(l,r,rs,deep+1,key);
    }
    int solve(int l,int r,int k) {
        int ll = 1 , rr = n , mm;
        while(ll < rr) {
            mm = (ll + rr + 1) >> 1;
            int tmp = query(l , r , 1 , 1 , mer[1][mm]) + 1;
            if(tmp <= k) ll = mm;
            else rr = mm - 1;
        }
        return mer[1][ll];
    }
    int main() {
        while(~scanf("%d%d",&n,&q)) {
            for(int i=1;i<=n;i++) scanf("%d" , &num[i]);
            build(1 , n , 1 , 1);
            int l , r , k;
            while(q--) {
                scanf("%d%d%d",&l,&r,&k);
                int ans = solve(l , r , k);
                printf("%d
    " , ans);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    【转】.net 在线播放各类视频
    引用母版页的内容页添加CSS文件
    NET上传大文件出现网页无法显示的问题 默认的上传文件大小是4M
    DropDownList1.Items.Insert 与 DropDownList1.Items.Add 的区别
    暑假集训8.10-网络流套树剖套线段树
    暑假集训8.10—网络流(黑白染色法)
    暑假集训8.7数据结构专题—网络流套线段树
    暑假集训8.7数据结构专题-线段树存直线
    暑假集训8.7数据结构专题-很妙的线段树( 觉醒力量(hidpower))
    可修改主席树&树上可修改主席树—树套树套树!!!
  • 原文地址:https://www.cnblogs.com/tobec/p/3235507.html
Copyright © 2011-2022 走看看