poj 2104 and hdu 2665 划分树模板入门题

来源:互联网 发布:linux 查看磁盘信息 编辑:程序博客网 时间:2024/05/21 22:39

题意:

给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。


解析:

划分树入门。

bing神的模板。

坑爹的地方是把-l 看成了-1........

一直re。


代码:

poj 2104:

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <set>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 1e5 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);int tree[30][maxn];     //表示每层每个位置的值int sorted[maxn];       //排完序的数int toleft[30][maxn];   //toleft[p][i]表示第p层从1到i有多少个数在左边void build(int l, int r, int dep){    if (l == r)        return;    int mi = (l + r) >> 1;    int same = mi - l + 1;          //等于中位数的数字个数    for (int i = l; i <= r; i++)    {        if (tree[dep][i] < sorted[mi])        {            same--;        }    }    int lpos = l;    int rpos = mi + 1;    for (int i = l; i <= r; i++)    {        if (tree[dep][i] < sorted[mi])//比中位数小        {            tree[dep + 1][lpos++] = tree[dep][i];        }        else if (tree[dep][i] == sorted[mi] && same > 0)        {            tree[dep + 1][lpos++] = tree[dep][i];            same--;        }        else                          //比中位数大        {            tree[dep + 1][rpos++] = tree[dep][i];        }        toleft[dep][i] = toleft[dep][l - 1] + lpos - l; // - l  不是减一    }    build(l, mi, dep + 1);    build(mi + 1, r, dep + 1);}//查询区间第k大数int query(int L, int R, int l, int r, int dep, int k){    if (l == r)        return tree[dep][l];    int mi = (L + R) >> 1;    int cnt = toleft[dep][r] - toleft[dep][l - 1];    if (k <= cnt)    {        int nextl = L + toleft[dep][l - 1] - toleft[dep][L - 1];        int nextr = nextl + cnt - 1;        return query(L, mi, nextl, nextr, dep + 1, k);    }    else    {        int nextr = r + toleft[dep][R] - toleft[dep][r];        int nextl = nextr - (r - l - cnt);        return query(mi + 1, R, nextl, nextr, dep + 1, k - cnt);    }}int main(){    #ifdef LOCAL    freopen("in.txt", "r", stdin);    #endif // LOCAL    int n, m;    while (~scanf("%d%d", &n, &m))    {        memset(tree, 0, sizeof(tree));        memset(toleft, 0, sizeof(toleft));        for (int i = 1; i <= n; i++)//start from 1        {            scanf("%d", &tree[0][i]);            sorted[i] = tree[0][i];        }        sort(sorted + 1, sorted + n + 1);        build(1, n, 0);        while (m--)        {            int fr, to, k;            scanf("%d%d%d", &fr, &to, &k);            printf("%d\n", query(1, n, fr, to, 0, k));        }    }    return 0;}

hdu 2665:

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <set>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 1e5 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);int tree[30][maxn];     //表示每层每个位置的值int sorted[maxn];       //排完序的数int toleft[30][maxn];   //toleft[p][i]表示第p层从1到i有多少个数在左边void build(int l, int r, int dep){    if (l == r)        return;    int mi = (l + r) >> 1;    int same = mi - l + 1;          //等于中位数的数字个数    for (int i = l; i <= r; i++)    {        if (tree[dep][i] < sorted[mi])        {            same--;        }    }    int lpos = l;    int rpos = mi + 1;    for (int i = l; i <= r; i++)    {        if (tree[dep][i] < sorted[mi])//比中位数小        {            tree[dep + 1][lpos++] = tree[dep][i];        }        else if (tree[dep][i] == sorted[mi] && same > 0)        {            tree[dep + 1][lpos++] = tree[dep][i];            same--;        }        else                          //比中位数大        {            tree[dep + 1][rpos++] = tree[dep][i];        }        toleft[dep][i] = toleft[dep][l - 1] + lpos - l; // - l  不是减一    }    build(l, mi, dep + 1);    build(mi + 1, r, dep + 1);}//查询区间第k大数int query(int L, int R, int l, int r, int dep, int k){    if (l == r)        return tree[dep][l];    int mi = (L + R) >> 1;    int cnt = toleft[dep][r] - toleft[dep][l - 1];    if (k <= cnt)    {        int nextl = L + toleft[dep][l - 1] - toleft[dep][L - 1];        int nextr = nextl + cnt - 1;        return query(L, mi, nextl, nextr, dep + 1, k);    }    else    {        int nextr = r + toleft[dep][R] - toleft[dep][r];        int nextl = nextr - (r - l - cnt);        return query(mi + 1, R, nextl, nextr, dep + 1, k - cnt);    }}int main(){    #ifdef LOCAL    freopen("in.txt", "r", stdin);    #endif // LOCAL    int ncase;    scanf("%d", &ncase);    while (ncase--)    {        int n, m;        scanf("%d%d", &n, &m);        memset(tree, 0, sizeof(tree));        memset(toleft, 0, sizeof(toleft));        for (int i = 1; i <= n; i++)//start from 1        {            scanf("%d", &tree[0][i]);            sorted[i] = tree[0][i];        }        sort(sorted + 1, sorted + n + 1);        build(1, n, 0);        while (m--)        {            int fr, to, k;            scanf("%d%d%d", &fr, &to, &k);            printf("%d\n", query(1, n, fr, to, 0, k));        }    }    return 0;}


0 0