线段树模板

线段树是acm中的重要数据结构,故整理一个模板以便以后用。

//线段树模板 其中Max存区间的最大值
//操作1:插入一个值到一个区间
//操作2:询问一个区间的最大值

#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;

#define  N  15000

//区间为[left , right]
struct node
{
	int left,right;
	int Max;
	int addLevel;     //记录线段树更新到此节点(此节点已经被更新)(表示其下的所有节点都需要更新,
                      //此处采用lazy更新),此是线段树精华所在
};

node tree[N * 4];

void buildTree(int n, int s,int e)
{
     tree[n].left = s;
	 tree[n].right = e;
     tree[n].Max = 0;
	 tree[n].addLevel = 0;

	 // 到达叶子节点
	 if(s == e)
	 {
          return;
	 }
	 else
	 {
          //递归建树
		 int mid = (s + e) >> 1;
		 //左子树[s,mid]
         buildTree(n << 1,s,mid);

		 //右子树[mid + 1,e]
		 buildTree((n << 1) + 1,mid + 1,e);
	 }


	 //一般都需要回溯计算父亲节点值
}

//将[s,e]区间更新
void insert(int n,int s,int e,int d)
{
    if(tree[n].left == s && tree[n].right == e)
	{
		tree[n].Max += d;
		tree[n].addLevel += d;
		return;
	}

	//进行lazy更新:更新其直接左右儿子节点,并更行左右儿子的addlevel值
    if(tree[n].addLevel)
	{
        tree[n << 1].Max += tree[n].addLevel;
		tree[n << 1].addLevel += tree[n].addLevel;

		tree[(n << 1) + 1].Max += tree[n].addLevel;
		tree[(n << 1) + 1].addLevel += tree[n].addLevel;

		tree[n].addLevel = 0;
	}

    int mid = (tree[n].left + tree[n].right) >> 1;
	if(mid >= e)
	{
         insert(n << 1,s,e,d);
	}
	else if(mid < s)
	{
         insert((n << 1) + 1,s,e,d);
	}
	else
	{
         insert(n << 1,s,mid,d);
		 insert((n << 1) + 1,mid + 1,e,d);
	}

	 //一般都需要回溯计算父亲节点值
	tree[n].Max = (tree[n << 1].Max > tree[(n << 1) + 1].Max ? 
				tree[n << 1].Max : tree[(n << 1) + 1].Max); 
}

int search(int n,int s,int e)
{
	if(tree[n].left == s && tree[n].right == e)
	{
		return(tree[n].Max);
	}

	//进行lazy更新:更新其直接左右儿子节点,并更行左右儿子的addlevel值
	if(tree[n].addLevel)
	{
		tree[n << 1].Max += tree[n].addLevel;
		tree[n << 1].addLevel += tree[n].addLevel;

		tree[(n << 1) + 1].Max += tree[n].addLevel;
		tree[(n << 1) + 1].addLevel += tree[n].addLevel;

		tree[n].addLevel = 0;
	}

	int mid = (tree[n].left + tree[n].right) >> 1;
	if(mid >= e)
	{
		return(search(n << 1,s,e));
	}
	else if(mid < s)
	{
		return(search((n << 1) + 1,s,e));
	}
	else
	{
		int l = search(n << 1,s,mid);
		int r = search((n << 1) + 1,mid + 1,e);
		return(l > r ? l : r);
	}
}

int main()
{
	int s,e,d,l;
	int lMax,rMax,lLoc,rLoc,t;
	while(scanf("%d",&l) != EOF)
	{
		memset(tree,0,sizeof(tree));
		buildTree(1,0,l);
		while(scanf("%d%d%d",&s,&e,&d))
		{
			if(s == -1) break;

			insert(1,s,e,d);
		}

		lMax = rMax = lLoc = rLoc = 0;
		for(int i = 0; i <= l ; ++i)
		{
			t = search(1,i,i);
			if(lMax < t)
			{
				lMax = t;
				lLoc = i;
			}

			if(rMax <= t)
			{
				rMax = t;
				rLoc = i;
			}
		}
		printf("%d %d\n",lLoc,rLoc);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值