题解【SP8002】HORRIBLE - Horrible Queries

题面

题解

这是一道线段树的模板题。

题目需要我们维护一个支持区间修改、区间查询的一个数据结构,很容易想到线段树。

然后发现和洛谷上线段树的模板1是同一道题。

由于本题中每个数的初始值都为\(0\),因此我们就不需要建树,直接开始把树上每个结点的值都初始化成\(0\)即可。

修改时寻找指定区间,维护一下\(lazy\ tag\)并更新节点的值即可。

查询时和修改同理,只是把查找更新的区间变成了加上区间的和。

注意:

  1. 数据有\(T\)组,因此每组数据开头都需要清空数组;
  2. \(lazy\ tag\)标记下传时要注意最后清空当前节点的\(lazy\ tag\)
  3. 需要开\(long\ long\)

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#define int long long
#define itn int
#define gI gi

using namespace std;

inline int gi()
{
	int f = 1, x = 0; char c = getchar();
	while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar();}
	return f * x;
}

int n, ans[100005 << 2], tag[100005 << 2];

inline int ls(int x) {return x << 1;}//左儿子
inline int rs(int x) {return x << 1 | 1;}//右儿子

inline void push_up(int x)//上传标记
{
	ans[x] = ans[ls(x)] + ans[rs(x)];//求和
}

inline void pushdown(int p, int l, int r)//下传标记
{
	if (tag[p])//如果还有标记
	{
		ans[ls(p)] = ans[ls(p)] + tag[p] * l;
		ans[rs(p)] = ans[rs(p)] + tag[p] * r;//加上和
		tag[ls(p)] = tag[ls(p)] + tag[p];
		tag[rs(p)] = tag[rs(p)] + tag[p];//加上标记
		tag[p] = 0;//清零标记
	}
}

void upd(int nl, int nr, int l, int r, int p, int k)//更新操作
{
	if (nl <= l && nr >= r)//当前区间包含于要更新的区间
	{
		ans[p] = ans[p] + (r - l + 1) * k, tag[p] = tag[p] + k;//加上和并记录lazy标记
		return;
	}
	int mid = (l + r) >> 1;
	pushdown(p, mid - l + 1, r - mid);//下传lazy标记
	if (nl <= mid) upd(nl, nr, l, mid, ls(p), k);//更新左区间
	if (nr > mid) upd(nl, nr, mid + 1, r, rs(p), k);//更新右区间
	push_up(p);//上传节点
}

int getans(int ql, int qr, int l, int r, int p)//求和操作,与更新同理
{
	int sum = 0;
	if (ql <= l && qr >= r) return ans[p];
	int mid = (l + r) >> 1;
	pushdown(p, mid - l + 1, r - mid);
	if (ql <= mid) sum = sum + getans(ql, qr, l, mid, ls(p));
	if (qr > mid) sum = sum + getans(ql, qr, mid + 1, r, rs(p));
	return sum;
}

signed main()
{
	int T = gi();
	while (T--)//多组数据
	{
	memset(tag, 0, sizeof(tag));
	memset(ans, 0, sizeof(ans));//多组数据记得清空数组
	int n = gi(), m = gi();
	for (int i = 1; i <= m; i++)
	{
		int fl = gi();
		if(fl == 0)//修改操作
		{
			int x = gi(), y = gi(), k = gi();
			upd(x, y, 1, n, 1, k);
		}
		else//求和操作
		{
			int x = gi(), y = gi();
			printf("%lld\n", getans(x, y, 1, n, 1));
		}
	}
	}
	return 0;//结束
}
posted @ 2019-08-17 21:24  csxsi  阅读(135)  评论(0编辑  收藏  举报