POJ -2104 K-th Number (线段树)

K-th Number

Time Limit: 20000MS Memory Limit: 65536K

Description
You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1…n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: “What would be the k-th number in a[i…j] segment, if this segment was sorted?”
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2…5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

Input
The first line of the input file contains n — the size of the array, and m — the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values — the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).

Output
For each question output the answer to it — the k-th number in sorted a[i…j] segment.

Sample Input
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output
5
6
3

之前的线段树用 sum[] 储存区间和或者区间最大值
这里用 vector<> 储存某一个区间排序好的结果。

另外位运算更快 用 ls=rt2, rs=rt2+1 就超时,用 ls=rt<<1, rs=rt<<1|1 就可以

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define long long ll
using namespace std;
const int maxn=100005;
int sum[maxn], n, q;
vector<int> dat[4*maxn];

void Buile_tree(int l, int r, int rt)
{
    if(l==r)
    {
        dat[rt].push_back(sum[l]);
        return;
    }
    int m=(l+r)>>1;
    int ls=rt<<1, rs=rt<<1|1;
    Buile_tree(l, m, ls);
    Buile_tree(m+1, r, rs);
    dat[rt].resize(r-l+1);//分配内存
    merge(dat[ls].begin(),dat[ls].end(),dat[rs].begin(),dat[rs].end(),dat[rt].begin());//将ls,rs两个子节点的排序结果合并到rt父结点上
}

int Query(int L, int R, int C, int l, int r, int rt)
{
    if(L>r||R<l)//[l,r]和[L,R]没有任何交集
        return 0;
    else if(L<=l&&r<=R)//[l,r]完全属于[L,R]
    {
        return upper_bound(dat[rt].begin(),dat[rt].end(),C)-dat[rt].begin();
    }
    else//[l,r]中的部分区间属于[L,R]
    {
        int m=(l+r)>>1;
        int lcnt=Query(L, R, C, l, m, rt<<1);
        int rcnt=Query(L, R, C, m+1, r, rt<<1|1);
        return lcnt+rcnt;
    }
}

int Search(int L, int R, int Ind)
{
    int l=-1e9-1;//l,r模拟某个值,而不是下标或范围
    int r=-l+2;
    while(l<r)//二分查找
    {
        int m=(l+r)>>1;
        int num=Query(L, R, m, 1, n, 1);//num为m在[L,R]内的下标
        if(num>=Ind)//此时说明m太大,r左移
            r=m;
        else
            l=m+1;
    }
    return l;
}

int main()
{
    scanf("%d%d", &n, &q);
    for(int i=1; i<=n; i++)
        scanf("%d", &sum[i]);
    Buile_tree(1, n, 1);
    int L, R, Ind;
    while(q--)
    {
        scanf("%d%d%d", &L, &R, &Ind);
        int ans=Search(L, R, Ind);
        printf("%d\n", ans);
    }
    return 0;
}

参考链接:
https://blog.csdn.net/a2459956664/article/details/51302474

你可能感兴趣的:(2018暑假ACM集训,#,ACM_线段树)