POJ2182 -- 线段树

一。线段树

线段树类似于区间树,它在每个节点之间保存一个区间:[a,b] , 那它左儿子保存的区间是:[a, (a+b)/2] ,右儿子保存的区间是:[(a+b)/2 +1 , b ]。

假设,父节点的标号为k, 那么左儿子的标号是2*k,右儿子的标号是2*k +1 .

假设,此时需要保存1-5的区间, 那么子节点的个数为5, 而线段树需要的空间约为3*5 =15个,即数组大小的3倍左右。

二。

POJ2182中构造的线段树为:(参加下图和代码)

typedef struct treeNode{
    int left;
    int right;
    int number;  //存放的是left和right这个区间,有几个数
}treeNode;
treeNode nodeArr[3*MAX]; //静态数组,

void buildSegTree(int node, int left, int right){
    nodeArr[node].left = left ;
    nodeArr[node].right = right;
    nodeArr[node].number = right -left +1; // [1,5] 之间有5个数
    if(left == right){
        return;
    }
    buildSegTree(node<<1, left, (left+right)>>1);  //node << 1 : node*2 ;  (left+right)>>1: (left+right)/2;
    buildSegTree((node<<1) +1, ((left+right)>>1) +1 , right);

}

在数节点treeNode中, 其中number值可以定义为自己所需要的值, 在这里是定义为这个区间有几头牛。

在构造树的时候,采用递归的方法,如果区间只有一个数,则返回,否则递归构造左右子树。

三。

该题的关键点在于,从最后一头牛开始,最后一头牛的编号为input[i]+1,且如果查找到该牛的编号,需要在它的树节点中,删除它的存在,即nodeArr[node].number--,也就是说区间1-3,原来有3头牛,查找到了编号为1的牛,那么区间1-3就还有2头牛;

还有一点需要注意的是,在查找右儿子的时候,查的是左起第number-nodeArr[2*node].number个数


查看全部代码:

#include <stdio.h>
#include <stdlib.h>
#define MAX 8001
int N;
int input[MAX];
int output[MAX];

typedef struct treeNode{
    int left;
    int right;
    int number;  //存放的是left和right这个区间,有几个数
}treeNode;

treeNode nodeArr[3*MAX]; //静态数组,

void buildSegTree(int node, int left, int right){
    nodeArr[node].left = left ;
    nodeArr[node].right = right;
    nodeArr[node].number = right -left +1; // [1,5] 之间有5个数
    if(left == right){
        return;
    }
    buildSegTree(node<<1, left, (left+right)>>1);  //node << 1 : node*2 ;  (left+right)>>1: (left+right)/2;
    buildSegTree((node<<1) +1, ((left+right)>>1) +1 , right);

}

int search(int node , int number){

    nodeArr[node].number--;

    if(nodeArr[node].left == nodeArr[node].right){
        return nodeArr[node].left;
    }


    if(nodeArr[2*node].number >= number){ //查左边
        return search(2*node,number);
    }
    if(nodeArr[2*node].number < number){  //查右边
        return search(2*node+1,number-nodeArr[2*node].number); //查右边的左起第number-nodeArr[2*node].number个数
    }
}

int main()
{
    memset(input, 0 ,sizeof(input));
    memset(output, 0 ,sizeof(output));
    memset(nodeArr, 0 ,sizeof(nodeArr));
    //freopen("input.txt","r",stdin);
    scanf("%d",&N);
    int i=2;
    for(i=2;i<=N;i++){
       scanf("%d",&input[i]);
    }
    input[1]=0;
    buildSegTree(1,1,N);

    for(i=N;i>0;i--){
        output[i] = search(1,input[i]+1);
    }

    for(i=1;i<=N;i++){
        printf("%d\n",output[i]);
    }

    return 0;
}


 

猜你喜欢

转载自blog.csdn.net/genius9_9/article/details/46501753