关于线段树

线段树的作用:

用于求解一些与线段有关的问题,如不规则图形求周长,面积。。。这类问题往往给出的条件是边(即线段)的长度。当然不排除直接对大量毫无关联的线段直接进行操作的问题。

线段树的语法:

线段树本质上是二叉树,只不过它的节点要表示一个范围,即线段的两个端点。倘若有其他需求可以在构造节点的结构体体里添加别的东西。

线段树的构造:

跟普通二叉树的构造类似,因为线段树每次都是把线段中分,因此需要一个变量来记录线段的中间值,这个值可以写在节点结构体里,也可以在代码段里写。

线段树的形式:

一般构造的都是叶节点是一个点,如[1, 1],[2, 2]。但是有时需要构造叶节点是一个最小单位的线段树,如[1, 2][2, 3]。个人感觉如求周长,面积之类的问题最好用叶节点是最小单位的线段树,因为即使你造了一个叶节点是点的线段树,那最后叶节点也不会被用到。

 

讲一个练习题(答案非原创,文章后面有原文链接,这里只做讲解):

现在有一面墙摆在龙马的前面,他老爸让他计算一下这面墙的面积有多少。然而这面
墙的高度并不是固定的。具体如图所示:

可怜的龙马,这一个人要算多久,于是他请来的被他打败过的朋友来帮他计算。
他的每个朋友通过测量之后会给龙马一个区间[l, r]和这个区间的高度。如果有重叠的部
分,取最高的高度。
通过朋友的返回值计算出墙的面积。

★数据输入

输入第一行有一个正整数n(1<=n<=10000),表示n 个回复。
接下来n 行,每行有三个数字l r h,表示区间[l, r]的高度为h。
计算过程中所有数据均在int 范围之内。

★数据输出

输出墙的面积。

★样例说明

区间[1, 5]高度为5, 区间[1, 3]高度为8,区间[4, 5]高度为9。所以实际墙的高度应为
区间[1, 3]高度为8,区间[3, 4]高度为5,区间[4, 5]高度为9。总面积S=8*(3-1)+5*(4-3)+9*(5-4)=30。

输入示例
31
5 5
1 3 8
4 5 9

输出示例
30

 

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #define MAXN 10010
 4 #define max(a,b) ((a)>(b))?(a):(b) 
 5 
 6 struct node{    
 7 int l,r,w;//w is the height
 8 }tree[MAXN<<1],seg_tree[MAXN<<2]; 
 9 int ans,n,seg[MAXN<<1],nodecnt; 
10 
11 //building segment tree, it is conmen skill.Actually, it always builds like such
12 void build(int v,int l,int r){    
13     int ls=v<<1,rs=ls+1,m;
14     seg_tree[v].l=l;
15     seg_tree[v].r=r;
16     if(l+1>=r)        return ;
17     m=(l+r)>>1;
18     build(ls,l,m);
19     build(rs,m,r);
20 }
21 
22 //there is no w in build function,so we will add it by struct[] tree.If there is some difficulty, take attention to the transion between tree, seg_tree and seg.seg sort of point,tree has all,
23 so operate seg and tree to add w to seg_tree
24 void insert(int v,int s,int e,int w){
25     int l=seg_tree[v].l,r=seg_tree[v].r,m=(l+r)>>1,ls=v<<1,rs=ls+1;
26     if(seg_tree[v].w>=w)        return ;
27     else if(s<=seg[l] && seg[r]<=e)        seg_tree[v].w=max(seg_tree[v].w,w);
28     else {
29         if(e<=seg[m])            insert(ls,s,e,w);
30         else if(s>=seg[m])            insert(rs,s,e,w);           else            insert(ls,s,seg[m],w), 
31                   insert(rs,seg[m],e,w);    
32     }
33 } 
34 
35 //compute (r-l)*w
36 void sum(int v){
37     int l,r,ls=v<<1,rs=ls+1;
38     l=seg_tree[v].l;
39     r=seg_tree[v].r;
40     if(l+1==r)        ans+=seg_tree[v].w*(seg[r]-seg[l]);     
41     else{
42         seg_tree[ls].w=max(seg_tree[ls].w,seg_tree[v].w);
43         seg_tree[rs].w=max(seg_tree[rs].w,seg_tree[v].w);
44         sum(ls);    sum(rs);
45     }
46 } 
47 
48 int main(){//  freopen("in.txt","r",stdin);     
49     int i;
50     scanf("%d",&n);
51     for(i=1;i<=n;++i){
52         scanf("%d%d%d",&tree[i].l,&tree[i].r,&tree[i].w);
53         seg[(i<<1)-1]=tree[i].l;
54         seg[i<<1]=tree[i].r;
55     }
56      std::sort(seg+1,seg+(n<<1)+1);
57 
58 //delete the repeat
59      for(i=nodecnt=1;i<=(n<<1);++i)
60         if(seg[i]!=seg[nodecnt])
61             seg[++nodecnt]=seg[i];
62 
63      build(1,1,nodecnt);
64      for(i=1;i<=n;++i)
65         insert(1,tree[i].l,tree[i].r,tree[i].w);
66      sum(1);
67      printf("%d\n",ans);
68      return 0;
69 }

 

参考博客:

http://hi.baidu.com/alpc62/blog/item/469edeca0043e382c8176875.html

http://www.cppblog.com/sicheng/archive/2008/01/09/40791.html

http://suneast.is-programmer.com/posts/19199.html

http://www.cppblog.com/abilitytao/archive/2010/07/21/120927.html

posted @ 2012-06-11 16:15  Mr. Sun  阅读(164)  评论(1编辑  收藏  举报