zoukankan      html  css  js  c++  java
  • 静态区间第k大(划分树)

    POJ 2104为例【经典划分树问题】

    思想:

    利用快速排序思想,

    • 建树时将区间内的值与区间中值相比,小于则放入左子树,大于则放入右子树,如果相等则放入左子树直到放满区间一半。
    • 查询时,在建树过程中利用leftsum[p][i]数组保存有多少个数划分到第p层,第i个位置的左边。每次查询计算出每个区间有多少数被放入左子树,小于等于k则说明所求数在左子树,继续查询其左子树,反之则查询右子树。l==r时则找到。
    • 时间复杂度O(nlogn+mlogn)

    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;//[]
    const int maxn = 100010;
    int tree[20][maxn];//每层每个位置的值
    int sorted[maxn];//排好序的数组,方便寻找中值
    int leftsum[20][maxn];//有多少个数分到该层该位置左边
    void build(int p, int l, int r)
    {
        if(l == r) return;
        int mid = (l + r)/2;
        int same = mid - l + 1;
        int x = sorted[mid];
        for(int i = l; i <= r; i++){
            if(tree[p][i] < x)  same--;
        }//与中值相等的数填满区间一半
        int tl = l, tr = mid + 1;
        for(int i = l; i <= r; i++){
            if(tree[p][i] < x)
                tree[p + 1][tl++] = tree[p][i];
            else if(tree[p][i] == x && same>0){
                tree[p + 1][tl++] = tree[p][i];
                same--;
            }else
               tree[p + 1][tr++] = tree[p][i];
            leftsum[p][i] = leftsum[p][l-1] + tl - l;
        }
        build(p + 1, l, mid);
        build(p + 1, mid + 1, r);
    }
    //[L,R]中的[l,r]的第k大数
    int query(int L, int R, int l, int r, int p, int k)
    {
        if(l == r) return tree[p][l];
        int mid = (L + R)/2;
        int cnt = leftsum[p][r] - leftsum[p][l-1];
        if(cnt >= k){
            int newl = L + leftsum[p][l-1] - leftsum[p][L-1];
            int newr = newl + cnt - 1;
            return query(L, mid, newl, newr, p+1, k);
        }else {
            int newr = r + leftsum[p][R] - leftsum[p][r];
            int newl = newr - (r - l - cnt);
            return query(mid+1, R, newl, newr, p+1, k - cnt);
        }
    }
    int main (void)
    {
        int n, m;scanf("%d%d",&n,&m);
        for(int i = 1; i <=n; i++){//下标从1开始
            scanf("%d",&tree[0][i]);
            sorted[i] = tree[0][i];
        }
        sort(sorted+1, sorted+n+1);
        build(0, 1,n);
        int s, t, k;
        while(m--){
            scanf("%d%d%d",&s,&t,&k);
            printf("%d
    ",query(1, n, s, t, 0, k));
        }
        return 0;
    }
    

    划分树还是挺好理解的,接下来看看归并树和主席树。

  • 相关阅读:
    sort函数详解
    C++重载运算符的规则详解
    poj3061-subsequence
    员工管理系统 :练习
    Jdbc 模拟登陆系统的练习
    有关String 的常用方法
    浅谈希尔排序-----摘录
    简单选择排序
    typedef 和define 的区别
    写博客的理由
  • 原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758794.html
Copyright © 2011-2022 走看看