题目描述
这是代码源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;
}