线段树

整理以前做ACM题目时候用的数据结构---线段树,说不定以后会用到。同时也当作复习。

线段树是一种高效的二叉搜索树,它比较侧重于对区间的计数操作,例如区间求和,区间最值,线段覆盖问题。以下代码为最基本的版本,只有区间求和。以后再陆续加上其它计数功能。


/*
对于线段树的每一个非叶子结点,设其表示区间为[a,b],则其左儿子表示的区间为[a,(a+b)/2],
右儿子的表示的区间为[(a+b)/2+1,b],叶结点表示的区间为[1,1],[2,2],[3,3]。。。

以下为区间[1,10]的一个例子
					     [1,10]
			 [1,5]				    [6,10]
		[1,3]     [4,5]          [6,8]     [9,10]
	[1,2] [3,3] [4,4] [5,5]   [6,7] [8,8] [9,9] [10,10] 
 [1,1] [2,2]               [6,6][7,7] 


当需要段更新时,设置一个延迟更新标记,不立即进行更新,当访问到有延迟标记的结点时,再去更新结点,然后将状态转给左右儿子

此版本为静态数组,效率比较高,但是对运行中树的大小有限制
*/


#include <iostream>
#include <stdlib.h>
template <class T>
class SegmentTree
{
    static const int maxsize = 50000*5;
    struct node
    {
        int l,r;
		int cover;//区间覆盖统计
		T sum;
		bool updateFlag;//延迟更新标记
    }s[maxsize];
	int right;//最右的端点,用于避免数组访问越界
public:
    void buildTree(int l,int r,int root,T v[])
    {
        s[root].l = l;
        s[root].r = r;

		//需要延迟更新,则设为true
		s[root].updateFlag = false;
        int mid = (l+r)>>1;

        if(r>l)
        {
            buildTree(l,mid,root*2,v);
            buildTree(mid+1,r,root*2+1,v);
            s[root].sum = s[root*2].sum + s[root*2+1].sum;
        }
        else
		{
            s[root].sum = v[l];

			//需要延迟更新,根据实际情况设定
			s[root].updateFlag = false;
		}
    }

	//将某个叶结点更新
    void update(int leafNode,T add,int root)
    {

		if(s[root].updateFlag)
		{
			//延迟更新操作,视具体情况而定
			s[root].updateFlag = false;
			if(root*2 < maxsize)
			{
				s[root*2].updateFlag = true;
				s[root*2+1].updateFlag = true;
				/*
				.............
				.............
				.............
				.
				.
				.
				.
				*/
			}
		}


		//该结点即为要更新的结点,当需要自底向上更新时
        if(s[root].l == leafNode && s[root].r == leafNode)
        {
            s[root].sum += add;

			//自底向上更新父结点
            root /= 2;
            while(root)
            {
                s[root].sum += add;
                root /= 2;
            }
        }
        else if(cur <= (s[root].l + s[root].r)/2)
            update(leafNode,add,root*2);
        else
            update(leafNode,add,root*2+1);
    }
	//查询区间的和
    T querry(int l,int r,int root)
    {
		//需要延迟标记有效,需要更新,根据实际情况修改
		if(s[root].updateFlag])
		{
			s[root].updateFlag = false;
			if(root*2 < maxsize)
			{
				s[root*2].updateFlag = true;
				s[root*2+1].updateFlag = true;
			}
			/*
			..
			..
			..
			..
			*/
		}
        if(s[root].l == l&& s[root].r == r) //该结点代表的区间恰好为所要求的区间,直接返回
            return s[root].sum;
        int mid = (s[root].l+s[root].r) >> 1;
        if(l > mid) //所求区间全部只在该结点的右儿子
            return querry(l,r,root*2+1);
        else if(r <= mid) //所求区间全部只在该结点的左儿子
            return querry(l,r,root*2);
        else //所求区间既在左儿子又在右儿子中
            return querry(l,mid,root*2) + querry(mid+1,r,root*2+1);
    }
	T querryInterval(int l,int r)
	{

		//出错,出错返回根据实际情况定义
		if(l > r)
			return NULL;
		return querry(int l,int r,1);
	}
};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值