zoukankan      html  css  js  c++  java
  • hdu 2665 Kth number (poj 2104 K-th Number) 划分树

    划分树的基本功能是,对一个给定的数组,求区间[l,r]内的第k大(小)数。

    划分树的基本思想是分治,每次查询复杂度为O(log(n)),n是数组规模。

    具体原理见http://baike.baidu.com/link?url=vIUKtsKYx7byeS2KCOHUI14bt_0sdHAa9BA1VceHdGsTv5jVq36SfZgBKdaHYUGqIGvIGrE_aJtqy0D0b1fCoq

    个人感觉看代码是最好的学习方法。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 100100
    
    int a[N];
    int s[30][N];//划分树
    int num[30][N];//num[i][j] - num[i][j-1] == 1表示第i层第j个数在下层中要被划入左子树
    
    void build(int l, int r, int dep = 1)
    {
        if(l == r){
            s[dep][l] = s[dep-1][l];
            return;
        }
        int mid = l+r>>1;
        int cnt = mid-l+1;
        for(int i = l; i <= r; i++) if(s[dep-1][i] < a[mid]) cnt--;
        int c1 = l, c2 = mid+1;
        for(int i = l; i <= r; i++)
        {
            if(s[dep-1][i] < a[mid] || ( s[dep-1][i] == a[mid] && cnt-- > 0)) s[dep][c1++] = s[dep-1][i];
            else s[dep][c2++] = s[dep-1][i];
    
            num[dep-1][i] = num[dep-1][l-1]+c1-l;
        }
        build(l, mid, dep+1);
        build(mid+1, r, dep+1);
    }
    
    int query(int l, int r, int k, int L, int R, int dep = 0)
    {
        if(l == r) return s[dep][l];
        int mid = L+R>>1;
        int cnt = num[dep][r] - num[dep][l-1];
    
        if(cnt >= k)
        {
            int nl = L+num[dep][l-1]-num[dep][L-1];
            int nr = nl+cnt-1;
            return query(nl, nr, k, L, mid, dep+1);
        }
        else
        {
            int nr = r+num[dep][R]-num[dep][r];
            int nl = nr - (r-l-cnt);
            return query(nl, nr, k-cnt, mid+1, R, dep+1);
        }
    }
    
    int main()
    {
        int T, n, m;
        scanf("%d", &T);
        while(T--)
        //while(~scanf("%d %d", &n, &m)) 
        {
            memset(num, 0, sizeof(num));
            scanf("%d %d", &n, &m);
            for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
            for(int i = 1; i <= n; i++) s[0][i] = a[i];
            sort(a+1, a+n+1);
            build(1, n);
            for(int i = 0; i < m; i++)
            {
                int l, r, k;
                scanf("%d %d %d", &l, &r, &k);
                printf("%d
    ", query(l, r, k, 1, n));
            }
    
        }
        return 0;
    }
  • 相关阅读:
    poj 3624 (背包入门)
    poj 2175(最消费用最大流消圈法判断是否为最小费用)
    poj 2195 (最小费用最大流)
    poj 3659 (树上的最小支配集)
    Codeforces Beta Round #76 (Div. 1 Only)
    poj 2516(最小费用最大流)
    2013 腾讯马拉松初赛 第0场
    批量重命名,把文件名中的(1)去掉。
    ms sql server 添加列,删除列。
    winform 获取当前程序所在目录。
  • 原文地址:https://www.cnblogs.com/beisong/p/4440700.html
Copyright © 2011-2022 走看看