一套线段树模板 忘记了是哪个题了—_— 想起来再补上

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#pragma warning(disable:4996)
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
ll sum[N<<2], add[N<<2];//sum是子节点总和 add是懒惰标记,每个数值需要加上多少.
struct NODE {
	int l, r;
	int mid() {
		return (l + r) >> 1;//在结构体中直接求出二者的mid
	}
}tree[N<<2];
void PushUp(int rt)
{
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void PushDown(int rt,int m)//把lazy标记打进去 m是区间长度
{
	if (add[rt])
	{
		add[rt << 1] += add[rt];
		add[rt << 1 | 1] += add[rt];
		sum[rt << 1] += add[rt] * (m - (m >> 1));
		sum[rt << 1 | 1] += add[rt] * (m >>1);
		add[rt] = 0;
	}
}
void BuildTree(int l,int r,int rt)
{
	tree[rt].l = l;
	tree[rt].r = r;
	add[rt] = 0;
	if (l == r)
	{
		scanf("%I64d",&sum[rt]);
		return;
	}
	int m = tree[rt].mid();
	BuildTree(l, m, rt<<1);
	BuildTree(m+1, r, rt<<1|1);
	PushUp(rt);
}
void UpdateTree(int c,int l,int r ,int rt )//c是懒惰标记 rt当前节点 l,r是要更新的区间
{//区间更新
	if (tree[rt].l == l && tree[rt].r == r)
	{
		add[rt] += c;
		sum[rt] += (ll)c * (r - l+1);
		return;
	}
	if (tree[rt].l == tree[rt].r)return;
	PushDown(rt, tree[rt].r - tree[rt].l + 1);
	int m = tree[rt].mid(); 
	if (r <= m)UpdateTree(c, l, r, rt << 1);
	else if (l > m)UpdateTree(c, l, r, rt << 1 | 1);
	else 
	{
		UpdateTree(c, l, m, rt << 1);
		UpdateTree(c, m + 1, r, rt << 1 | 1);
	}
	PushUp(rt);
}
ll query(int l,int r,int rt)
{
	if (tree[rt].l == l && tree[rt].r == r)
		return sum[rt];
	PushDown(rt,tree[rt].r-tree[rt].l+1);//记得把之前打的懒惰标记 传下去
	int m = tree[rt].mid();
	ll res = 0;
	if (r <= m)res += query(l, r, rt << 1);
	else if (l > m)res += query(l, r, rt << 1 | 1);
	else 
	{
		res += query(l, m , rt << 1 );
		res+= query(m+1, r, rt << 1 | 1);
	}
	return res;
}
int main()
{
	int q, n;
	int a, b,c;
	ll ans;
	while (scanf("%d%d",&n,&q)!=EOF)
	{
		BuildTree(1,n,1);
		while (q--)
		{
			char ch[3];
			scanf("%s", ch);
			if (ch[0] == 'Q')
			{
				scanf("%d%d",&a,&b);
				ans = query(a, b, 1);
				printf("%lld\n",ans);
			}
			else if (ch[0] == 'C')
			{
				scanf("%d%d%d",&a,&b,&c);
				UpdateTree( c, a, b, 1);
			}
		}
	}
	return 0;
}

懒惰标记(避免更新速度太慢)

在增加时,如果要加的区间正好覆盖一个 节点,则增加其节点的Inc值,不再往下走 ,否则要更新nSum(加上本次增量),再将增 量往下传。这样更新的复杂度就是O(log(n)) 
 
在查询时,如果待查区间不是正好覆盖一 个节点,就将节点的Inc往下带,然后将Inc 代表的所有增量累加到nSum上后将Inc清0 ,接下来再往下查询。 一边查询,一边Inc往 下带的过程也是区间分解的过程,复杂度也是 O(log(n)) 

猜你喜欢

转载自blog.csdn.net/qq_17175221/article/details/81235131
今日推荐