poj 2104 K-th Number(划分树)

题目链接:http://poj.org/problem?id=2104

题目分析:该问题给定一段区间中的值,再给定一段查询区间[ql, qr],需要给出该查询区间中的值在排序后的第K大的值;

使用划分树即可解决该问题;划分树的建树的复杂度为O(NlogN),查询一个区间的第K大值的复杂度为O(logN);

代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAX_N = 100000 + 10;
int sorted[MAX_N];
int to_left[20][MAX_N];
int tree[20][MAX_N];

void Build(int l, int r, int deep)
{
    if (l == r) return;
    int mid = (l + r) >> 1;
    int lc_same = mid - l + 1;
    int l_pos = l, r_pos = mid + 1;

    for (int i = l; i <= r; ++i)
    {
        if (tree[deep][i] < sorted[mid])
            lc_same--;
    }

    for (int i = l; i <= r; ++i)
    {
        if (tree[deep][i] < sorted[mid])
            tree[deep + 1][l_pos++] = tree[deep][i];
        else if (tree[deep][i] == sorted[mid] && lc_same > 0)
        {
            lc_same--;
            tree[deep + 1][l_pos++] = tree[deep][i];
        }
        else
            tree[deep + 1][r_pos++] = tree[deep][i];
        to_left[deep][i] = to_left[deep][l - 1] + l_pos - l;
    }
    Build(l, mid, deep + 1);
    Build(mid + 1, r, deep + 1);
}

int Query(int l, int r, int ql, int qr, int deep, int k)
{
    if (l == r)
        return tree[deep][l];
    int mid = (l + r) >> 1;
    int cnt = to_left[deep][qr] - to_left[deep][ql - 1];

    if (cnt >= k)
    {
        int new_ql = l + to_left[deep][ql - 1] - to_left[deep][l - 1];
        int new_qr = new_ql + cnt - 1;
        return Query(l, mid, new_ql, new_qr, deep + 1, k);
    }
    else
    {
        int new_qr = qr + to_left[deep][r] - to_left[deep][qr];
        int new_ql = new_qr - (qr - ql - cnt);
        return Query(mid + 1, r, new_ql, new_qr, deep + 1, k - cnt);
    }
}

int main()
{
    int n, query_times;

    scanf("%d %d", &n, &query_times);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &tree[0][i]);
        sorted[i] = tree[0][i];
    }

    sort(sorted + 1, sorted + n + 1);
    Build(1, n, 0);
    for (int i = 0; i < query_times; ++i)
    {
        int ql, qr, k, ans;

        scanf("%d %d %d", &ql, &qr, &k);
        ans = Query(1, n, ql, qr, 0, k);
        printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-10-03 23:53:29

poj 2104 K-th Number(划分树)的相关文章

【POJ 2104】 K-th Number 主席树模板题

达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没有评测,但我立下flag这个代码一定能A.我的同学在自习课上考语文,然而机房党都跑到机房来避难了\(^o^)/~ #include<cstdio> #include<cstring> #include<algorithm> #define for1(i,a,n) for(i

poj 2104 K-th Number(划分树模板)

划分树模板题,敲上模板就ok了. #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define MP

[NBUT 1458 Teemo]区间第k大问题,划分树

裸的区间第k大问题,划分树搞起. #pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #inc

POJ 2104 区间第K大值(划分树做法)

由于深感自己水平低下,把大部分有效时间放在了刷题上,于是好久没写题解了.今天刚学了下划分树的原理,于是写道简单题练练手. 题目链接:http://poj.org/problem?id=2104 划分树的空间复杂度和时间复杂度均为O(nlogn),对于解决该问题而言,每次查询的复杂度为O(logn),比归并树O((log)^3)节省时间[归并树采用了三次二分]. 但是划分树也有自己的缺点,不支持更新以及适用范围狭窄,总之...是时代的眼泪了= = AC代码: #include <iostream>

poj 2104 K-th Number (划分树入门)

题意:给n个数,m次询问,每次询问L到R中第k小的数是哪个 算法:划分树 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 7 const int mx=1e5+5; 8 int tree[30][mx]; 9 int sortt[mx]; 10 int sum[30][mx]; 11 12 vo

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 <c

POJ 2761-Feed the dogs(划分树)求区间内第k小的数

Feed the dogs Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 17679   Accepted: 5561 Description Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the

杭电ACM2665——Kth number~~划分树

题目的意思:给点区间[a, b],查找第K大的数,和POJ2104题一样,只是HDU上的时间限制5000MS,用我在POJ上的方法,过不了,会超时. 而这一题的代码,改一下main函数的输入,就可以直接AC了POJ上的2104. 这题,用分桶法,WR,纠结了一晚上,最后还是放弃了,实在不知道错在哪里.于是改用了划分树的方法,学习了划分树的建立和查找. 划分树:主要运用于求解序列中区间[a, b]上的第K大的数,也就是区间[a, b]从小到大排序,第K个. 主要的算法思路是: 1,建树:先排序好存

poj2104--K-th Number(划分树)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 40169   Accepted: 13120 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse