代码源:878、简单差分

277 阅读3分钟

logo.png

题目描述

这是代码源5月10日的div2每日一题

简单差分 - 题目 - Daimayuan Online Judge

给定一个长度为 n 数组 A,执行以下操作 m 次:

选择一段区间 [l,r],将区间中所有的数加上整数 x。

操作完成后回答 k 个问题:

每个问题给定一段区间 [l,r],输出区间中所有数的和。

输入格式

第一行三个正整数 n,m,k。

接下来一行 n 个数,表示数组 A。

接下来 m 行,每行输入三个整数 l,r,x。

接下来 k 行,每行输入两个整数 l,r。

输出格式

输出 k 行,每行一个数表示对应问题的和。

样例输入

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

样例输出

18

数据规模

对于全部数据,保证 1≤n≤2×105,1≤m,k≤105,|x|≤105。

\

问题解析

两个解法:

一:差分+前缀和

既然题目都说简单差分了,那就用差分写,因为这题的区间加操作都是前面一次性加完再询问区间和,所以我们可以先做出数组的差分数组,再通过差分数组实现区间加的过程。之后用前缀和将差分数组还原成普通数组,再进行一次前缀和做出前缀和数组,这样我们就可以O1的时间复杂度下求出数组的区间和。

(这题数据读入比较大,要用快一点的输入输出:scanf或者关流同步或者快读)

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	ll n, m, q, x, y, w;
	cin >> n >> m >> q;
	vector<ll>v(n+1), s(n + 1),f(n+1);
	for (int i = 0; i < n; i++)
	{
		cin >> v[i];
		if (i == 0)f[i] = v[i];
		else f[i] = v[i] - v[i - 1];
	}
	while (m--)
	{
		cin >> x >> y >> w;
		f[x-1] += w;
		f[y] -= w;
	}
	s[0] = f[0];
	for (int i = 1; i < n; i++)s[i] = s[i - 1] + f[i];
	for (int i = 1; i < n; i++)s[i] += s[i - 1];
	
	while (q--)
	{
		cin >> x >> y;
		cout << s[y-1] - (x == 1 ? 0 : s[x - 2]) << endl;
	}
	return 0;
}

二、线段树+lz标记

说到区间问题肯定就是线段树,经典的区间和+区间加

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50;
ll a[N], f[4 * N], b[4 * N];

void pushdown(int k, int l, int r)
{
	if (b[k] != 0)
	{
		int m = (l + r) / 2;
		b[k + k] += b[k];
		b[k + k + 1] += b[k];
		f[k + k] += b[k] * (m - l + 1);
		f[k + k + 1] += b[k] * (r - m);
		b[k] = 0;
	}
}

void buildtree(int k, int l, int r)
{
	if (l == r)
	{
		f[k] = a[l];
		return;
	}
	int m = (l + r) / 2;
	buildtree(k + k, l, m);
	buildtree(k + k + 1, m + 1, r);
	f[k] = f[k + k] + f[k + k + 1];
}

void add(int k, int l, int r, int x, int y, int w)
{
	if (l == x && r == y)
	{
		f[k] += (r - l + 1) * w;
		b[k] += w;
		return;
	}
	int m = (l + r) / 2;
	pushdown(k, l, r);
	if (y <= m)add(k + k, l, m, x, y, w);
	else
		if (x > m)add(k + k + 1, m + 1, r, x, y, w);
		else add(k + k, l, m, x, m, w), add(k + k + 1, m + 1, r, m + 1, y, w);
	f[k] = f[k + k] + f[k + k + 1];
}

ll calc(int k, int l, int r, int x, int y)
{
	if (x == l && r == y)return f[k];
	int m = (l + r) / 2;
	pushdown(k, l, r);
	ll res = 0;
	if (y <= m)res = calc(k + k, l, m, x, y);
	else
		if (x > m)res = calc(k + k + 1, m + 1, r, x, y);
		else res = calc(k + k, l, m, x, m) + calc(k + k + 1, m + 1, r, m + 1, y);
	f[k] = f[k + k] + f[k + k + 1];
	return res;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 1; i <= n; i++)cin >> a[i];
	buildtree(1, 1, n);
	while (m--)
	{
		int x, y, w;
		cin >> x >> y >> w;
		add(1, 1, n, x, y, w);
	}
	//for (int i = 5; i <= n; i++)cout << calc(1, 1, n, i, i) << endl;
	while (q--)
	{
		int x,y;
		cin >> x >> y;
		cout << calc(1, 1, n, x, y) << endl;
	}
	return 0;
}