POJ 2104 K-th Number 归并树

来源:互联网 发布:数组发筛选100以内素数 编辑:程序博客网 时间:2024/05/22 01:54

题目:

http://poj.org/problem?id=2104

题意:

求区间[l,r]内第k小的元素

思路:

用划分树,主席树,平方分割写过这道题,用归并树搞一下。归并树就是在建树的时候对数组进行归并排序,并保存每一步的归并结果,因此从树的底部到树的顶部就是归并排序的实现过程。然后二分枚举答案,对归并树进行查询,挺好理解的,就是效率不怎么高,这四种方法,按效率排序:划分树>主席树>归并树>平方分割

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int N = 100010;struct node{    int l, r;}s[N*4];int arr[N], seg[20][N];void build(int l, int r, int dep, int k){    s[k].l = l, s[k].r = r;    if(l == r)    {        seg[dep][l] = arr[l];        return;    }    int mid = (l + r) >> 1;    build(l, mid, dep + 1, k << 1);    build(mid + 1, r, dep + 1, k << 1|1);    int i = l, j = mid + 1, p = l;    while(i <= mid && j <= r)    {        if(seg[dep+1][i] < seg[dep+1][j]) seg[dep][p++] = seg[dep+1][i++];        else  seg[dep][p++] = seg[dep+1][j++];    }    while(i <= mid) seg[dep][p++] = seg[dep+1][i++];    while(j <= r) seg[dep][p++] = seg[dep+1][j++];}int query(int l, int r, int dep, int k, int x){    if(s[k].l > r || s[k].r < l) return 0;    if(l <= s[k].l && s[k].r <= r)        return upper_bound(&seg[dep][s[k].l], &seg[dep][s[k].r]+1, x) - &seg[dep][s[k].l];    return query(l, r, dep + 1, k << 1, x) + query(l, r, dep + 1, k << 1|1, x);}int main(){    int t, n, m;    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &n, &m);        for(int i = 1; i <= n; i++) scanf("%d", &arr[i]);        build(1, n, 1, 1);        while(m--)        {            int i, j, k;            scanf("%d%d%d", &i, &j, &k);            int l = 1, r = n, res;            while(l <= r)            {                int mid = (l + r) >> 1;                int tmp = query(i, j, 1, 1, seg[1][mid]);                if(tmp >= k) res = mid, r = mid - 1;                else l = mid + 1;            }            printf("%d\n", seg[1][res]);        }    }    return 0;}
0 0
原创粉丝点击