poj 2104 划分树

看到这题时确实没有想到一个好的方法解题,纠结了很久之后搜了题解,原来解问题固定的算法,划分树。

划分树是靠线段树作为辅助工具,原理和快排相似。

划分树建树的过程和快速排序很类似,构建起来也比较简单,关键是在查询操作不太好理解。

poj 2104 AC代码:

#include 
#include 
#include 
using namespace std;

const int maxn = 100000+10;
const int DEEP = 20;
struct node {
    int l, r;
    int mid() {
        return (l+r)>>1;
    }
}v[maxn<<2];
int data[maxn];//保存排序之后的数组
int seg[DEEP][maxn];//保存第d层划分之后的数组
int lessMid[DEEP][maxn];//保存第d层在i之前(包括i)小于data[mid]的数的数目

void build(int l, int r, int n, int d) {
    v[n].l = l, v[n].r = r;
    if (l==r) return ;
    int mid = v[n].mid();
    int lsame = mid-l+1;//确定与data[mid]相等并且被划分到左侧的数目
    for (int i=l; i<=r; ++i)
        if (seg[d][i]data[mid])
            seg[d+1][tr++] = seg[d][i];
        else if (seg[d][i]same) {//说明相等时左侧没放满
                ++same;
                ++lessMid[d][i];
                seg[d+1][tl++] = seg[d][i];
            }
            else//相反,左侧放满了,现在放在右侧
                seg[d+1][tr++] = seg[d][i];
        }
    }
    build(l, mid, n<<1, d+1);
    build(mid+1, r, n<<1|1, d+1);
}
int query(int l, int r, int n, int k, int d) {
    if (l==r)
        return seg[d][l];
    int s;//区间[l,r]中有多少小于data[mid]的数被放在左边
    int ss;//区间[v[n].l,l-1]中有多少小于data[mid]的数被放在左边
    if (l==v[n].l)
        ss = 0;
    else
        ss = lessMid[d][l-1];
    s = lessMid[d][r] - ss;
    if (s>=k) {
        int newl = v[n].l+ss;
        int newr = v[n].l+ss+s-1;
        return query(newl, newr, n<<1, k, d+1);
    }
    else {
        int mid = v[n].mid();
        int bb = l-v[n].l -ss;//区间[v[n].l,l-1]中有多少个数被放在右边
        int b = r-l+1 -s;//区间[l,r]中有多少个数被放在右边
        int newl = mid+bb+1;
        int newr = mid+bb+b;
        return query(newl, newr, n<<1|1, k-s, d+1);
    }
}
int main()
{
    int n, m;
    while (~scanf("%d%d", &n, &m))
    {
        for (int i=1; i<=n; ++i)
        {
            scanf("%d", &data[i]);
            seg[1][i] = data[i];
        }
        sort(data+1, data+n+1);
        build(1, n, 1, 1);
        while (m--)
        {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            printf("%d\n", query(l, r, 1, k, 1));
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构)