关于线段树
线段树的作用:
用于求解一些与线段有关的问题,如不规则图形求周长,面积。。。这类问题往往给出的条件是边(即线段)的长度。当然不排除直接对大量毫无关联的线段直接进行操作的问题。
线段树的语法:
线段树本质上是二叉树,只不过它的节点要表示一个范围,即线段的两个端点。倘若有其他需求可以在构造节点的结构体体里添加别的东西。
线段树的构造:
跟普通二叉树的构造类似,因为线段树每次都是把线段中分,因此需要一个变量来记录线段的中间值,这个值可以写在节点结构体里,也可以在代码段里写。
线段树的形式:
一般构造的都是叶节点是一个点,如[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