AcWing 1264. 动态求连续区间和(线段树区间查询模板)

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 1264. 动态求连续区间和(线段树区间查询模板)相关的知识,希望对你有一定的参考价值。

题目链接

https://www.acwing.com/problem/content/1266/

思路

虽然这题可以用树状数组或者不带lazy标记的线段树做,但是我写了带 lazy 标记的线段树做,并且封装成了一个结构体,方便以后写线段树的题目,详情可以参考下面的代码,因为题目比较简单,就不多赘述了

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

#define ll long long

const int N = 1e5+10;

ll a[N];

struct Tnode
	ll l,r,sum,lazy;
;

struct SegmentTree
	
	Tnode tree[N<<2];
	
	inline void init_lazy(ll root)//清空lazy标记
		tree[root].lazy = 0;
	
	
	inline void union_lazy(ll fa,ll son)//向下推lazy标记
		tree[son].lazy = tree[fa].lazy + tree[son].lazy;
	
	
	inline void cal_lazy(ll root)//将当前节点的lazy的权计算如sum中
		tree[root].sum = tree[root].sum + (tree[root].r - tree[root].l + 1) * tree[root].lazy;
	
	
	inline void push_up(ll root)//向上更新
		tree[root].sum = tree[root<<1].sum + tree[(root<<1) | 1].sum;
	
	inline void push_down(ll root)//向下更新
		if(tree[root].lazy != 0)
			cal_lazy(root);//第一步计算lazy标记
			if(tree[root].l != tree[root].r)//第二不,下推lazy标记
				union_lazy(root,root<<1);
				union_lazy(root,(root<<1) | 1);
			
			init_lazy(root);//第三步,清空root的lazy标记,因为已经下推过了
		
	
	
	void build(ll l,ll r,ll root)//建树
		tree[root].l = l;
		tree[root].r = r;
		init_lazy(root);//初始化lazy节点
		if(l == r) tree[root].sum = a[l];
		else
			ll mid = ((r+l) >> 1);
			build(l,mid,root<<1);
			build(mid+1,r,(root<<1)+1);
			push_up(root);
		
	
	void update(ll l,ll r,ll root,ll add)//区间更新,在 [l,r] 区间都加上add
		if(tree[root].l >= l && tree[root].r <= r)
			tree[root].sum += add * (r-l+1);//由于是区间更新所有要乘上区间长度
			tree[root].lazy = add;//这里的懒标记直接标记为add就好了
		
		else
			push_down(root);//向下更新,因为有可能还存在lazy节点没更新
			ll mid = ((tree[root].r+tree[root].l) >> 1);
			if(l <= mid) update(l,r,root<<1,add);
			if(r > mid)  update(l,r,(root<<1)+1,add);
			push_up(root);//向上更新
		
	
	ll query(ll l,ll r,ll root) //区间查询
		if(tree[root].l >= l && tree[root].r <= r) return tree[root].sum;
		else
			push_down(root);//下推标记,可能还有lazy节点没更新
			ll mid = tree[root].l + ((tree[root].r-tree[root].l) >> 1);
			ll ans = 0LL;
			if(l <= mid) ans += query(l,r,root<<1);//如果我们查询区间的左边界比当前节点的中间点小,那么说明查询区间要往左走
			if(r > mid)  ans += query(l,r,(root<<1) + 1);//如果我们查询的右边界要比当前节点的中间节点大,那么说明查询区间要往右走
			return ans;
		
	
Tree;

int n,m;

int main()

	cin>>n>>m;
	for(int i = 1;i <= n; ++i) cin>>a[i];
	Tree.build(1,n,1);
	ll k,l,r;
	for(int t = 1;t <= m; ++t)
		cin>>k>>l>>r;
		if(k)
			Tree.update(l,l,1,r);
		else
			cout<<Tree.query(l,r,1)<<endl;
		
	

/*

Testcase:
input

10 5
1 2 3 4 5 6 7 8 9 10

output:

11
30
35
*/

以上是关于AcWing 1264. 动态求连续区间和(线段树区间查询模板)的主要内容,如果未能解决你的问题,请参考以下文章

POJ 题目3667 Hotel(线段树,区间更新查询,求连续区间)

AcWing 246. 区间最大公约数

HDU 1264 Counting Squares(线段树求面积的并)

UVALive - 3938 分治,线段树,求动态最大连续和

动态求区间K大值(权值线段树)

HDU 1540 Tunnel Warfare(区间合并)线段树