数据结构----线段树----线段树的基本算法

来源:互联网 发布:如何申请淘宝小号涮单 编辑:程序博客网 时间:2024/05/29 19:33

一、建树算法

建树算法很简单也很重要,建树算法是对线段树的一个初始化操作,

如图:

因为建树的代码比较简单,所以就直接发出来了:

void build(int i, int l, int r){    int mid;    tree[i].l=l;tree[i].r=r;    if(r==l) return;    mid=(l+r)/2;    build(i*2,l,mid);    build(i*2+1,mid+1,r);}


二、插入算法

插入算法就是一堆if语句,但是要根据题目的情况来写,每一个插入算法都不同,以下题为例:


影子的宽度

题目描述

桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?

输入

第1行:3个整数L,R,N。-100000 <=L<=R<= 100000,表示墙所在的区间;1<=N<=100000,表示盒子的个数
接下来N行,每行2个整数BL, BR,-100000 <=BL<=BR<= 100000,表示一个盒子的左、右端点(左闭右开)

输出

第1行:1个整数W,表示影子的总宽度。

样例输入

Sample Input 10 7 21 24 5Sample Input 2-10 10 2-5 2-2 2Sample Input 3-10 10 3-7 0-4 9-4 2Sample Input 4-100 100 3-7 25 92 5Sample Input 5-50 50 4-2 40 69 10-5 30

样例输出

Sample Output 12Sample Output 27Sample Output 316Sample Output 416Sample Output 535


这一道题求的就是投影面积的总长度,我们可以在结构体里加一个变量cover,cover表示l~r之间的区间是否被阴影完全覆盖,插入操作就是对cover变量的更新,有两种写法:
1、
void insert(int i,int l,int r){int mid;if(tree[i].cover==1) return;//当前区间已经覆盖,返回mid=(tree[i].l+tree[i].r)/2;if(l==tree[i].l&&r==tree[i].r)//恰好与当前区间重合tree[i].cover=1;else if (r <= mid)//仅在左子区间insert(i * 2, l, r);else if (l >= mid + 1)insert(i * 2 + 1, l, r);//仅在右子区间else//分在左右区间{insert(i * 2, l, mid);insert(i * 2 + 1, mid + 1, r);}}

这一种写法分的情况比较多,而且容易写错,于是有了下面的简便写法
2、
void insert(int i,int l,int r){if(r<tree[i].l||tree[i].r<l) return;if(l<=tree[i].l&&tree[i].r<=r){tree[i].cover=1;return;}insert(i*2,l,r);insert(i*2+1,l,r);}
这种写法的意思是,把插入的线段区间与每一个线段树节点区间进行比较,
如果完全覆盖,cover=1,
如果没有完全覆盖,就继续递归,
如果完全没有覆盖,就退出,因为再找下去也没有意义了。

三、统计算法

这个比较简单,就直接发代码吧。

int count(int i){if(tree[i].cover==1) return tree[i].r-tree[i].l+1;else if(tree[i].l==tree[i].r ) return 0;else return count(i*2)+count(i*2+1);}
这个算法相当于把整个线段树进行了一次遍历,时间复杂度O(n^2),

还有一个写法是改变cover的定义,cover的新定义是l~r区间覆盖长度的总和,最后输出tree[1].cover就可以了,时间复杂度O(1)。



1 0
原创粉丝点击