POJ2182 -- 线段树

来源:互联网 发布:qq飞车改车吧 软件 编辑:程序博客网 时间:2024/04/30 04:32

一。线段树

线段树类似于区间树,它在每个节点之间保存一个区间:[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 8001int 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;}


 

0 0