hdu 4251 The Famous ICPC Team Again

hdu 4251 The Famous ICPC Team Again 划分树
//hdu 4251 The Famous ICPC Team Again

//划分树



//求中位数(就是求中间大的)

//建树和查找,模板题,看代码

//不懂可以看看这人写的

//http://www.cnblogs.com/183zyz/archive/2012/08/01/2618295.html



#define infile freopen("in.txt", "r", stdin);

#include <stdio.h>

#include <string.h>

#include <algorithm>

#define N 100005



using namespace std;



struct NODE

{

    int l, r;

}tree[4*N];





int sorted[N], level[20][N];//level记录每一层每个段的序列

int l_cnt[20][N];   //记录left到right中进入



void build(int left, int right, int loc, int dep)

{

    tree[loc].l = left;

    tree[loc].r = right;

    if(left == right)

        return;



    int mid = left + (right-left)/2;



    int mid_val = sorted[mid];



    int cnt = 0;    //记录小于left到right这段的中值的个数

    for(int i = left; i <= right; ++i)

        if(level[dep][i] < mid_val)

            cnt++;



    //这里l_tot是从left开始···

    int l_tot = left, r_tot = mid + 1;

    int equal_cnt = 0;  //equal_cnt记录跟mid_val相等且进入左子树的个数

    for(int i = left; i <= right; ++i)

    {

        if(level[dep][i] < mid_val) //小于mid_val的进入左子树

            level[dep+1][l_tot++] = level[dep][i];

        else if(level[dep][i] == mid_val && mid-left+1 - cnt > equal_cnt)

        {   //等于mid_val的且没超过左子树限定个数的时候进入左子树

            equal_cnt++;

            level[dep+1][l_tot++] = level[dep][i];

        }

        else

            level[dep+1][r_tot++] = level[dep][i];

        l_cnt[dep][i] = l_tot - left;   //记录进入左子树的个数

    }

    build(left, mid, 2*loc, dep+1);

    build(mid+1, right, 2*loc+1, dep+1);

}



int ans;

void find(int loc, int from, int to, int dep, int aim)

{

    int left = tree[loc].l, right = tree[loc].r;

    if(left == right)

    {

        ans = level[dep][left];

        return;

    }

    int mid = left + (right-left)/2;



    //l_from记录当前层中,from以前的数进入左子树的个数(不包括from这个数)

    //l_to记录当前层中,to以前的数进入又子树的个数,包括to

    int l_from, l_to = l_cnt[dep][left+to-1];

    if(from > 1)

        l_from = l_cnt[dep][from+left-2];

    else

        l_from = 0;



    //接下去那层就应该保持和这层一样的起点,即from左边的个数不变

    //若下一层到左子树,则要从from以左的进入左子树的个数(from_cnt)开始

    //由于from这个数也到左子树所以下一层应从from_cnt+1开始

    //若下一层到右子树要去掉进入左子树的个数

    if(l_to - l_from >= aim)    //from到to之间进入左子树的个数

        find(2*loc, l_from+1, l_to, dep+1, aim);

    else

        find(2*loc+1, from-1-l_from+1, to-l_to, dep+1, aim-(l_to-l_from));

}



int main()

{

    //infile

    int n, n_case = 1;;

    while(scanf("%d", &n) != EOF)

    {

        printf("Case %d:\n", n_case++);

        for(int i = 1; i <= n; ++i)

        {

            scanf("%d", &level[1][i]);

            sorted[i] = level[1][i];

        }

        sort(sorted+1, sorted+n+1);

        build(1, n, 1, 1);

        int n_query;

        scanf("%d", &n_query);

        while(n_query--)

        {

            int from, to;

            scanf("%d%d", &from, &to);

            find(1, from, to, 1, (to-from)/2+1);

            printf("%d\n", ans);

        }

    }

    return 0;

}

 

你可能感兴趣的:(ICPC)