线段树

来源:互联网 发布:csdn 算法 编辑:程序博客网 时间:2024/05/18 09:13

        树结构的基本思想是分割。普通二叉搜索树是按照对象来进行划分,因此效果往往和数据结构内对象有关;而线段树是根据关键码的可能范围来分的,这种技术叫做关键空间分解。

        线段树的处理对象是线段(一般意义上的区间也可以看成是线段),它把线段组织成利于检索和统计的形式,它的本质是线段的二叉搜索树。但是线段可以分解和合并,线段树又有一些一般二叉树没有的特殊的操作。另外,线段树操作的是整个区间,它的渐进时间效率不依赖于数据结构中的对象。

       线段树的定义:线段树是一颗二叉搜索树,最终将一个区间[1,n]划分为一些[i, i+1]的单元区间,每个单元区间对应线段树中的一个节点。每个节点用变量count记录覆盖该节点的线段条数。

       线段树处理的对象:线段树的处理对象时一段狭窄的区间,区间上的格点对应有限个固定的变量,好像是线性的数组用完全二叉排序树形式表达。处理问题的时候,抽象出区间上的格点,也即是明确每个格点对应变量的含义。

       线段树的实现和空间耗费:如果节点i的处理对象时区间[a,b],那么区间[a,(a+b)/2]和[(a+b)/2,b]分别是i左儿子和右儿子的处理对象。当求解区间[a,b]内某个参数的统计值时,可以直接调用i上的统计信息,而无需将区间[a,a]->[b,b]的信息一个个累加。这是线段树在时间效率上主要的优点。和堆及二叉树相同,线段树也是动态维护的数据结构。空间复杂度最坏情况下是满二叉树。

       线段树的插入和删除:显然,算法是基于二分的。和一般的BST不一样的是,只要考虑的总区间不变,线段树的节点本身是不变的。改变的知识计数器Ci和其他信息。

       线段树的扩充:除了完全覆盖区间的线段条数Ci之外,往往还需要记录两个量来帮助我们获得更多的信息:

              测度m:节点所表示区间中线段覆盖过的长度

              独立线段树line:指的是区间中互不相交的线段条数

              权和sum:区间所有元线段的权和。


HDU(1166):

#include <iostream>#include <stdio.h>#include <cstdlib>#include <string.h>#include <algorithm>using namespace std;#define N 50005struct SegmentTree {int l, r, mid;int sum;}ST[4*N];int data[N];inline void init(int l, int r, int n) {ST[n].l = l;ST[n].r = r;ST[n].mid = (l+r)>>1;ST[n].sum = 0;if (l+1 == r)return;init(l, (l+r)>>1, 2*n);init((l+r)>>1, r, 2*n+1);};inline void add(int pos, int value, int n) {ST[n].sum += value;if (ST[n].l + 1 == ST[n].r)return;if (pos < ST[n].mid) {add(pos, value, 2*n);} else {add(pos, value, 2*n+1);}};inline void sub(int pos, int value, int n) {ST[n].sum -= value;if (ST[n].l + 1 == ST[n].r)return;if (pos < ST[n].mid) {sub(pos, value, 2*n);} else {sub(pos, value, 2*n+1);}};inline int query(int l, int r, int n) {if (ST[n].l == l && ST[n].r == r)return ST[n].sum;if (l < ST[n].mid) {if (r <= ST[n].mid) {return query(l, r, 2*n);} else {return query(l, ST[n].mid, 2*n) + query(ST[n].mid, r, 2*n+1);}} else {return query(l, r, 2*n+1);}};int main(){    //freopen("C://Users//smile//Desktop//in.txt","r",stdin);    //freopen("C://Users//smile//Desktop//out.txt","w",stdout);int T, cas = 1;scanf("%d",&T);while (T --) {int n, tmp;char in[10];scanf("%d",&n);init(1, n+1, 1);for (int i = 1; i <= n; ++ i) {scanf("%d",&tmp);add(i, tmp, 1);}printf("Case %d:\n",cas++);while (scanf("%s",in), strcmp(in,"End")) {int l, r;scanf("%d%d",&l,&r);if (in[0] == 'Q') {printf("%d\n", query(l, r+1, 1));} else if (in[0] == 'A') {add(l, r, 1);} else {sub(l, r, 1);}}}    //fclose(stdin);    //fclose(stdout);}





原创粉丝点击