题目描述
小明在练习绝世武功, nn 个练功桩排成一排,一开始每个桩的损伤为 00。
接下来小明会练习 mm 种绝世武功,每种武功都会对 [l, r][l,r] 区间分别造成 [s,e][s,e] 的伤害。
这个伤害是一个等差序列。例如 l = 1, r = 4, s = 2, e = 8l=1,r=4,s=2,e=8 ,则会对 1-41−4 号练功桩造成2, 4, 6, 82,4,6,8 点损伤。
小明想让你统计一下所有练功桩的损伤的和。
输入描述
第一行输入 n, mn,m,代表练功桩的数量和绝世武功的种类数。
接下来 mm 行输入 44 个整数 l, r, s, el,r,s,e 。
1 \leq n \leq 10^7 , 1\leq m \leq 3 \times 10 ^ 5 , 1\leq l, r \leq n1≤n≤107,1≤m≤3×105,1≤l,r≤n
输出描述
输出一个整数代表所有练功桩的损伤和, 题目保证所有输入输出都在 [0, 9 \times 10^{18}][0,9×1018]
输入输出样例
示例 1
6 2
1 5 2 10
2 4 1 1
33
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
原题链接:https://www.lanqiao.cn/problems/1368/learning/
做法一:朴素做法:
#include <iostream>
using namespace std;
const long long int N = 10000010, M =300010;
int a[N], q[N];
int main()
{
long long int l, r, s, e;
long long int n, m;
scanf("%lld %lld",&n,&m);
long long int res = 0;
while(m --)
{
scanf("%lld %lld %lld %lld", &l, &r, &s, &e);
res += (s + e) * (r - l + 1) / 2;
}
cout << res << endl;
return 0;
}
做法二:二阶差分:
#include<iostream>
#define ll long long
using namespace std;
const int N = 1e7 + 10;
ll c[N];
int main()
{
int n, m; cin >> n >> m;
while (m--)
{
int l, r, s, e;
cin >> l >> r >> s >> e;
int d = (e - s) / (r - l);
c[l] += s;
c[l + 1] += d - s;
c[r + 1] -= d + e;
c[r + 2] += e;
}
for (int i = 1; i <= n; i++)
{
c[i] += c[i - 1];
}
ll sum = 0;
for (int i = 1; i <= n; i++)
{
c[i] += c[i - 1];
sum += c[i];
}
cout << sum << endl;
return 0;
}
二阶差分的公式: