POJ 3468 - A Simple Problem with Integers | 线段树板子题

整理一下线段树的模板。

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
using namespace std;

#define lson i << 1
#define rson i << 1 | 1
#define ll long long 
const int MAX_N = 100005;//题目描述n 1e5
int a[MAX_N];//存放需要放进树的数据

//定义树的节点
struct node
{
	int l, r;//节点表示范围
	ll lazy;//lazy跟新延迟标记

	//sum节点属性
	ll sum;

	inline int len()//管辖区间内元素的数目
	{
		return r - l + 1;
	}

	//针对区间和问题的update
	inline void update(ll val)
	{
		lazy += val;
		//对父亲节点+个数*val,不查询子叶节点就不下放
		sum += 1LL * len() * val;//1LL防止int溢出,转为ll
	}
}tree[MAX_N << 2];//x<<2 = x*2^2 


/**回溯跟新**/
void push_up(int i)
{
	tree[i].sum = tree[lson].sum + tree[rson].sum;
}


/**下放标记**/
void push_down(int i)//i号节点
{
	ll lazy = tree[i].lazy;
	if (lazy == 0)
		return;

	tree[lson].update(lazy);
	tree[rson].update(lazy);
	tree[i].lazy = 0;
}

/**建立线段树**/
void build(int i, int l, int r)//1, 1, n
{
	tree[i].l = l;
	tree[i].r = r;

	tree[i].lazy = tree[i].sum = 0;

	if (l == r)
	{
		tree[i].sum = a[l];
		return;
	}

	int mid = (l + r) >> 1;

	build(lson, l, mid);
	build(rson, mid + 1, r);

	push_up(i);//建立的过程中顺带区间统计
}


/**更新线段树**/
void update(int i, int l, int r, int val)//1, l, r, +c
{
	//缩到目标范围时 ,对父亲节点调用struct内部的update函数
	if (tree[i].l == l && tree[i].r == r)	
	{
		tree[i].update(val);
		return;
	}

	//走到这里说明还没到达合适的目标范围

	push_down(i);//lazy下放

	int mid = (tree[i].l + tree[i].r) >> 1;

	if (r <= mid)//目标右边界比当前mid还小,必然往左找
		update(lson, l, r, val);

	else if (l > mid)//目标左边界比当前mid还大,必然往右找
		update(rson, l, r, val);

	else//l <= mid <= r
	{
		update(lson, l, mid, val);
		update(rson, mid + 1, r, val);
	}

	//如果是刚刚好的情况,那么i是不用更新的(直接update)
	//但是对于上面的分支,可能这个父亲节点的i不是恰好统治这个范围
	//所以就要逐层更新上去
	push_up(i);
}

/**查询**/
ll query(int i, int l, int r)
{
	if (tree[i].l == l && tree[i].r == r)//缩到目标区间
	{
		return tree[i].sum;
	}

	//因为要查询,所以下放lazy
	push_down(i);
	
	int mid = (tree[i].l + tree[i].r) >> 1;

	if (r <= mid)
		return query(lson, l, r);
	
	else if (l > mid)
		return query(rson, l, r);
	
	else
		return query(lson, l, mid) + query(rson, mid + 1, r);
}



///
OFF MUBAN//
//


int main()
{
	//假如有通过1/0或字母指定操作operation
	char op[10];

	int N, //数字个数
		Q; //询问/操作个数
	scanf("%d %d", &N, &Q);//N

	//读入数据
	for (int i = 1; i <= N; ++i)
		scanf("%d", &a[i]);

	//建树
	build(1, 1, N);


	//进行操作
	for (int i = 1; i <= Q; ++i)
	{
		scanf("%s", op);
		if (op[0] == 'Q')//查询区间和
		{
			int l, r;
			scanf("%d %d", &l, &r);
			printf("%lld\n", query(1, l, r));
		}
		else//‘C’ 区间内都+val
		{
			int l, r, val;
			scanf("%d %d %d", &l, &r, &val);
			update(1, l, r, val);
		}
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值