划分树 poj 2104

划分树

划分树的定义

它的每一个节点保存区间[lft, rht]所有元素,元素排列顺序与原数组(输入)相同,但是,两个子树的元素为该节点所有元素排序后 rht−lft +1  / 2个进入左子树,其余的到右子树,同时维护一个num域,num[i]  表示lft 到i这些点有多少进入了左子树。

数据结构

int Sort[M];//排完序的数组,便于后面查找一段线段的最中间的数

struct node{

    int val[M];//记录第几层的位置保存那个值

    int num[M];//记录从lft到i这些点多少个进入左子树

}t[20];//不同的层,见下面的例子

输入 :1 2 3 44 5 6 8

排完序:1 2 3 4 4 5 6 8

建树:[1,5,6,3,8,4,4,2]    

      [1,3,4,2][5,6,8,4]

      [1,2][3,4][5,4][6,8]

      [1][2][3][4][4][5][6][8]

标记红色的表示进入下一层的左节点

划分树的建立Build

划分树的建立和普通的二叉树的建立过程差不多,一开始排序原数组的一个copy,每次在树的一层根据排好序的数组对这个节点长度的数进行操作,具体就是把一半的数存入下一层左节点,一半的数存在右节点,当然是左节点数小于右节点的数最小值,不断维护num的值,num值的作用是方便查找

void build_tree(intlft,int rht,intp){在第p层区间[lft,rht]建树

    if(lft==rht)return ;//只有一个节点直接返回

    int i,mid =md(lft,rht);//区间中点

    int isame =mid-lft+1,same = 0;//假设一开始区间的左半部分所有的数都和这个区间最中间,i的数相等isame,same标记多少个相等的放在左节点了

    for(i =lft;i<=rht;i++)

        if(t[p].val[i]<Sort[mid])isame--;///这样可以求出左边有多少个数要放和Sort[mid]相等

    int ln =lft,rn = mid+1;

    for(i =lft;i<=rht;++i){

        if(i==lft)t[p].num[i]=0;//特别处理特殊情况

        elset[p].num[i]=t[p].num[i-1];

        ///处理三种可能小于 大于 等于,等于还要注意是否已经放够了相等的数

        if(t[p].val[i]<Sort[mid]){

            t[p].num[i]++;

            t[p+1].val[ln++]=t[p].val[i];

        }else if(t[p].val[i]>Sort[mid]){

            t[p+1].val[rn++]=t[p].val[i];

        }else {

            if(same<isame){

                same++;

                t[p].num[i]++;

                t[p+1].val[ln++]=t[p].val[i];

            }else{

                t[p+1].val[rn++]=t[p].val[i];

            }

        }

    }

    ///递归对子节点建树

    build_tree(lft,mid,p+1);

    build_tree(mid+1,rht,p+1);

}

划分树的查找

在区间[a,b]上查找第k大的元素当前树节点的区间[lft,rht]

1.       如果t[p].num[b]−t[p].num[a−1]>=k,  即区间[a,b]进入p的左孩子的个数已经超过k个,那么就往左孩子里面查找,同时更新a,b

a = lft+t[p].num[a-1],b=lft+t[p].num[b]-1;

这个要自己仔细想一下了,结合上面树的结构和num的作用,其实就是不断缩短查找区间

2.       否则,即[a,b]进入p的左孩子的个数小于k个,那么就要往右孩子查找第 (k-s)大的数,同理,a = mid+1+(a-lft-t[p].num[a-1])括号部分表示[lft,a-1]多少个进入有p的右子树,清楚了吧。b同理,自己想想。。

int query(int a,int b,int k,int p,int lft,int rht){

    if(lft==rht)return t[p].val[lft];

    int s,ss,b2,bb,mid=md(lft,rht);

    if(a==lft){

        s = t[p].num[b];

        ss = 0;

    }else {

        s = t[p].num[b]-t[p].num[a-1];

        ss = t[p].num[a-1];

    }

    if(s>=k){

        a = lft+ss;

        b = lft+ss+s-1;

        returnquery(a,b,k,p+1,lft,mid);

    }else {

        bb = a-lft-ss;

        b2 = b-a+1-s;

        a = mid+bb+1;

        b = mid+bb+b2;

        returnquery(a,b,k-s,p+1,mid+1,rht);

    }

}

完整的code 取自poj 2104

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

#define M 100002

#define md(x,y) (((x)+(y))>>1)

int Sort[M];

struct node{

    int val[M];

    int num[M];

}t[20];

void build_tree(intlft,int rht,intp){//??[lft,rht],̨²p?

    if(lft==rht)return ;

    int i,mid =md(lft,rht);

    int isame =mid-lft+1,same = 0;

    for(i =lft;i<=rht;i++)

        if(t[p].val[i]<Sort[mid])isame--;

    int ln =lft,rn = mid+1;

    for(i =lft;i<=rht;++i){

        if(i==lft)t[p].num[i]=0;

        elset[p].num[i]=t[p].num[i-1];

        if(t[p].val[i]<Sort[mid]){

            t[p].num[i]++;

            t[p+1].val[ln++]=t[p].val[i];

        }else if(t[p].val[i]>Sort[mid]){

            t[p+1].val[rn++]=t[p].val[i];

        }else {

            if(same<isame){

                same++;

                t[p].num[i]++;

                t[p+1].val[ln++]=t[p].val[i];

            }else{

                t[p+1].val[rn++]=t[p].val[i];

            }

        }

    }

    build_tree(lft,mid,p+1);

    build_tree(mid+1,rht,p+1);

}

int query(int a,int b,int k,int p,int lft,int rht){

    if(lft==rht)return t[p].val[lft];

    int s,ss,b2,bb,mid=md(lft,rht);

    if(a==lft){

        s = t[p].num[b];

        ss = 0;

    }else {

        s = t[p].num[b]-t[p].num[a-1];

        ss = t[p].num[a-1];

    }

    if(s>=k){

        a = lft+ss;

        b = lft+ss+s-1;

        returnquery(a,b,k,p+1,lft,mid);

    }else {

        bb = a-lft-ss;

        b2 = b-a+1-s;

        a = mid+bb+1;

        b = mid+bb+b2;

        returnquery(a,b,k-s,p+1,mid+1,rht);

    }

}

int main()

{

    int n,m,k;

    scanf("%d%d",&n,&m);

    for(int i = 0;i<n;++i){

        scanf("%d",&t[0].val[1+i]);

        Sort[i+1] = t[0].val[i+1];

    }

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

    build_tree(1,n,0);

    /*for(int i =0;i<=3;i++){

        printf("\nnum[i]:\t");

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

        printf("%d ",t[i].num[j]);

    }   */

    for(int i = 0;i<m;i++){

        intst,ed;

        scanf("%d%d%d",&st,&ed,&k);

        printf("%d\n",query(st,ed,k,0,1,n));

    }

    return 0;

}

猜你喜欢

转载自blog.csdn.net/sysucph/article/details/8523335