poj3468(线段树区间查询+区间更新)

思路:很明显的线段树模板题,区间查询+区间更新

但是小弟比较菜,并不会线段树,所以现学了一波,别的还是好理解的,就是lazy标记我觉得很难理解(应该是因为我比较菜),所以请教了大佬,大佬告诉我:lazy标记就是在访问这个节点时,并且要访问子节点时,向下传递lazy标记,以减少时间;访问操作包含了(查询与更新);

代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;
/*
poj3468 线段树区间更新,区间查询
坑点:数据会超过int
*/
struct SegTree
{
	int l, r;//区间端点 
	long long  val;//区间值 
	long long lazy;//当访问到这个节点并且要访问子节点的时候,向下传递标记
			//访问包括了更新跟查询操作 
}segtree[410000];
void pushup(int root)//更新父节点 
{
	segtree[root].val = segtree[root << 1].val + segtree[root << 1 | 1].val;
}
void pushdown(int root)
{
	segtree[root << 1].lazy += segtree[root].lazy;
	segtree[root << 1 | 1].lazy += segtree[root].lazy;
	segtree[root << 1].val += (segtree[root << 1].r - segtree[root << 1].l + 1)*segtree[root].lazy;
	segtree[root << 1 | 1].val += (segtree[root << 1 | 1].r - segtree[root << 1 | 1].l + 1)*segtree[root].lazy;
	segtree[root].lazy = 0;

}
void build(int root, int left, int right)
{
	segtree[root].l = left;
	segtree[root].r = right;
	if (left == right)
	{
		scanf("%lld", &segtree[root].val);
		return;
	}
	int mid = (left + right) >> 1;
	build(root << 1, left, mid);//建左子树
	build(root << 1 | 1, mid + 1, right);//建右子树
	pushup(root);//根据左右子树确定父节点 
}
long long query(int root, int qleft, int qright)
{
	if (qleft <= segtree[root].l&&qright >= segtree[root].r)
	{
		return segtree[root].val;
	}
	pushdown(root);
	long long ans = 0;
	int mid = (segtree[root].l + segtree[root].r) >> 1;
	if (qleft <= mid)
	{
		ans += query(root << 1, qleft, qright);
	}
	if (qright > mid)
	{
		ans += query(root << 1 | 1, qleft, qright);
	}
	return ans;
}
void add(int root, int qleft, int qright, long long val)
{
	if (qleft <= segtree[root].l&&qright >= segtree[root].r)//如果当前区间在所求区间中 
	{
		segtree[root].val += (segtree[root].r - segtree[root].l + 1)*val;
		segtree[root].lazy += val;
		return;
	}
	pushdown(root);
	int mid = (segtree[root].l + segtree[root].r) >> 1;
	if (qleft <= mid)
	{
		add(root << 1, qleft, qright, val);
	}
	if (qright > mid)
	{
		add(root << 1 | 1, qleft, qright, val);
	}
	pushup(root);
}
int main()
{
	int n, m;
	char op[10];
	scanf("%d%d", &n, &m);
	build(1, 1, n);
	while (m--)
	{
		scanf("%s", op);
		if (op[0] == 'Q')//查询 
		{
			int a, b;
			scanf("%d%d", &a, &b);
			printf("%lld\n", query(1, a, b));
		}
		else if (op[0] == 'C')
		{
			int a, b, val;
			scanf("%d%d%d", &a, &b, &val);
			add(1, a, b, val);
		}
	}
	//system("pause");
	return 0;
}
/*
10 1000
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值