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