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