区间和(单点修改,区间查询)(线段树)

题目描述

这是一道模板题。给定数列 a[1], a[2], \dots, a[n] ,
你需要依次进行 q 个操作,
操作有两类:
1 i x:给定 i,x ,将 a[i] 加上 x ;
2 l r:给定 l,r ,求 \sum_{i=l}^ra[i] 的值(换言之,求 a[l]+a[l+1]+\dots+a[r] 的值)。

输入格式

第一行包含 2 个正整数 n,q ,表示数列长度和询问个数。保证 1\le n,q\le 10^6 。
第二行 n 个整数 a[1], a[2], \dots, a[n] ,表示初始数列。保证 |a[i]|\le 10^6 。
接下来 q 行,每行一个操作,为以下两种之一:1 i x:给定 i,x ,将 a[i]加上 x;2 l r:给定 l,r ,求 \sum_{i=l}的值。保证 1\le l\le r\le n, |x|\le 10^6 。

输出格式

对于每个 2 l r 操作输出一行,每行有一个整数,表示所求的结果。

样例

样例输入
3 2
1 2 3
1 2 0
2 1 3
样例输出
6

数据范围与提示

对于所有数据, 1\le n,q\le 10^6, |a[i]|\le 10^6 , 1\le l\le r\le n, |x|\le 10^6 。

思路: 线段树的模板题,也可以用树状数组解决,树状数组内存更小。

#include 
#include 
#include 
#include 
#define ls(x) x << 1 //2 * x
#define rs(x) x << 1 | 1 //2 * x + 1

using namespace std;

typedef long long ll;

const int maxn = 1e6 + 5;

int n, m;
ll a[maxn], ans[4 * maxn], add[4 * maxn]; //开4倍大小的数组,add是标记,ans是答案

void push_up(int x)
{
	ans[x] = ans[ls(x)] + ans[rs(x)];
}

//优化输入
inline int read()
{
	int s = 0, w = 1;
	char ch = getchar();

	while (ch < '0' || ch > '9')
	{
		if (ch == '-')
			w = -1;
		ch = getchar();
	}

	while (ch >= '0' && ch <= '9')
	{
		s = s * 10 + ch - '0';
		ch = getchar();
	}

	return s * w;
}


//建树
void build(int x, int l, int r)
{
	add[x] = 0;
	
	if (l == r)
	{
		ans[x] = a[l];
		return;
	}

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

	build(ls(x), l, mid);
	build(rs(x), mid + 1, r);

	push_up(x);
}


//标记下传
void push_down(int x, int l, int r)
{
	int mid = (l + r) >> 1;

	add[ls(x)] += add[x];
	add[rs(x)] += add[x];
	ans[ls(x)] += add[x] * (mid - l + 1);
	ans[rs(x)] += add[x] * (r - mid);
	
	add[x] = 0;
}


//更改
void change(int nl, int nr, int l, int r, int x, ll k)
{
	if (nl <= l && r <= nr)
	{
		ans[x] += k * (r - l + 1);
		add[x] += k;
		return;
	}

	push_down(x, l, r);

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

	if (nl <= mid)change(nl, nr, l, mid, ls(x), k);
	if (mid + 1 <= nr)change(nl, nr, mid + 1, r, rs(x), k);
	
	push_up(x);
}


//查询
ll query(int ql, int qr, int l, int r, int x)
{
	ll res = 0;

	if (ql <= l && r <= qr)return ans[x];

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

	push_down(x, l, r);

	if (ql <= mid)res += query(ql, qr, l, mid, ls(x));
	if (mid + 1 <= qr)res += query(ql, qr, mid + 1, r, rs(x));

	return res;
}

int main()
{
	n = read();
	m = read();

	for (int i = 1; i <= n; ++i)
		a[i] = read();

	build(1, 1, n);

	while (m--)
	{
		int judge = read();
		int x = read();
		int y = read();
		ll k;

		if (judge == 1)
			change(x, x, 1, n, 1, y);
		else if (judge == 2)
			printf("%lld\n", query(x, y, 1, n, 1));
	}

	return 0;
}

你可能感兴趣的:(数据结构,线段树)