poj3264_线段树

昨晚写了一个线段树的程序,各种bug,最后硬是AC了,这个题的大意是这样的:

给n个数字,然后在给出一些区间范围(s,e),求出在这个区间范围内的最大值和最小值,总结一下这个题,我一共有5个bug

1.建立线段树时,类似完全二叉树,一开始我开的数组是最大数字个数的2倍多一点,然后开始悲剧,每当程序执行到Build_Tree()时就死了,一开始百思不得其解,后来自己用手模拟了一下建树的过程,发现虽然类似完全二叉树,但还不都是。完全二叉树只有最底层是叶子节点,但是线段树不一定,比如对(1,6)建树,模拟一下就会知道,最后改成开成3倍就OK了,纠结啊。

2.第二个问题是编程基础不好导致的,我在初始化时就对线段树的每一个节点的最大值和最小值都赋值为0,这样做使得无效节点会影响有效节点,应该改为最大值为0,最小值大于题目范围内的值。

3.最主要的,以[1,7]为根建树,注意这里不是以插入的数字与m进行比较,而是以位置pos:1--n进行比较。这也让我瞬间想起来之前看过一些大牛的模版,直接先建立线段树的叶子节点(即依次从 i:1--n 插入每一个数字),然后在建立上层节点。而我的做法是从根节点开始到叶子节点,耗时o(lgn)。

4.在插入每个节点的过程中,忘记对非叶子节点的最大值和最小值进行记录了。需要在递归结束(即知道左右孩子的记录)后,对父节点进行记录。

5.就是大数据读写的时候要用scanf,和printf代替cin和cout

一下是线段树的代码:

View Code
  1 #include <iostream>
  2 #include <stdio.h>
  3 using namespace std;
  4 
  5 const int maxnum=50005;
  6 const int maxx=1000005;
  7 
  8 typedef struct
  9 {
 10     int l;
 11     int r;
 12     int big;
 13     int small;
 14 }tree;
 15 
 16 tree list[maxnum*3];   //这里为什么是3,先想想,一开始弄成2*maxnum+10都错。
 17 
 18 void Init()
 19 {
 20     int i;
 21     for(i=0;i<maxnum*2+10;i++)
 22     {
 23         list[i].big=0;   //big and small 不能都是0
 24         list[i].small=maxx; //这里一开始将big和small都设成0了,这样small一直是0,郁闷。
 25     }
 26 }
 27 
 28 void Build_Tree(int l,int r,int cur)
 29 {
 30     list[cur].l=l;
 31     list[cur].r=r;
 32     if(l==r) return;
 33     else
 34     {
 35         int m=(l+r)/2;
 36         Build_Tree(l,m,2*cur+1);
 37         Build_Tree(m+1,r,2*cur+2);
 38     }
 39 }
 40 
 41 void Insert(int pos,int num,int cur)  //终于知道为什么有的博客里要先依次建立叶子节点,然后才建立内部节点了
 42 {                                     //这里可以根据i:1--n做比较插入节点
 43     if(list[cur].l==list[cur].r)
 44     {
 45         list[cur].big=list[cur].small=num;
 46         return ;
 47     }
 48     int m=(list[cur].l+list[cur].r)/2;
 49     if(pos<=m) Insert(pos,num,cur*2+1);
 50     else Insert(pos,num,cur*2+2);
 51 
 52     list[cur].big=list[cur*2+1].big>=list[cur*2+2].big?list[cur*2+1].big:list[cur*2+2].big;
 53     list[cur].small=list[cur*2+1].small<=list[cur*2+2].small?list[cur*2+1].small:list[cur*2+2].small;
 54     //这里一开始没有写,唉。
 55 }
 56 
 57 
 58 int check_big(int l,int r,int cur)
 59 {
 60     if(list[cur].l==l && list[cur].r==r)
 61         return list[cur].big;
 62 
 63     int m=(list[cur].l+list[cur].r)/2;
 64     if(m<l) return check_big(l,r,cur*2+2);
 65     else if(m>=r) return check_big(l,r,cur*2+1);
 66     else
 67     {
 68         int s1=check_big(l,m,cur*2+1);
 69         int s2=check_big(m+1,r,cur*2+2);
 70         return s1>=s2?s1:s2;
 71     }
 72 }
 73 
 74 int check_small(int l,int r,int cur)
 75 {
 76     if(list[cur].l==l && list[cur].r==r)
 77         return list[cur].small;
 78     int m=(list[cur].l+list[cur].r)/2;
 79     if(m<l) return check_small(l,r,cur*2+2);
 80     else if(m>=r) return check_small(l,r,cur*2+1);
 81     else
 82     {
 83         int s1=check_small(l,m,cur*2+1);
 84         int s2=check_small(m+1,r,cur*2+2);
 85         return s1<=s2?s1:s2;
 86     }
 87 }
 88 
 89 int main()
 90 {
 91     Init();
 92     Build_Tree(1,maxnum,0);
 93     int n,q,cow;
 94     scanf("%d%d",&n,&q);
 95 
 96     int i;
 97     for(i=1;i<=n;i++)
 98     {
 99         scanf("%d",&cow);  //用cin错了
100         Insert(i,cow,0);  //Insert(cow,0)这里错了
101     }
102 
103     int l,r;
104     for(i=0;i<q;i++)
105     {
106         scanf("%d%d",&l,&r);
107         int s1=check_big(l,r,0);
108         int s2=check_small(l,r,0);
109         printf("%d\n",s1-s2);
110     }
111     return 0;
112 }

此题也是tju oj2762

posted @ 2012-07-12 18:52  pushing my way  阅读(208)  评论(0编辑  收藏  举报