P3655 不成熟的梦想家 (未熟 DREAMER)
题目描述
我们Aqours的成员共有N+1人,他们会列成一队。
他们的唱功以A[0]到A[N]表示,A[i](0≤i≤N)均给出。
学园都市的机器可以改变队列中连续多个成员的唱功值,并将其加上一个数Z,当然当Z是负数的时候就变成减去了。
我打算一共使用这个机器Q次,每次把第X到第Y号(1≤X,Y≤1e6)的成员都加上Z点唱功值。
而我们队伍的魅力值B,是这么算的:
一开始B=0,然后从第1号到第N号成员,
- 当Ai−1<Ai:B=B−S⋅∣Ai−1−Ai∣
- 当Ai−1>Ai:B=B+T⋅∣Ai−1−Ai∣ 其中S和T是LoveLive组委会给我们的常数。
果然,我是バカチカ(笨蛋千歌)呢,所以作为领导我永远排在队伍的开头,唱功永远是0,机器也不会改到我头上呢。
你能帮我们算算,我每次使用完这个机器之后,成员的魅力B是多少吗?
输入格式
第一行4个整数,N,Q,S,T,各个变量在描述中已经解释
接下来N+1行,每行一个数整数Ai,其中A0=0
接下来Q行,每行3个整数,X,Y,Z各个变量在描述中已经解释
输出格式
Q个整数,表示答案。
输入输出样例
输入 #1复制
4 3 2 3 0 5 2 4 6 1 2 1 3 4 -3 1 4 2
输出 #1复制
-9 -1 -5
说明/提示
100%的数据 1≤N,Q≤200000;1≤S,T,Ai≤1e6;∣Z∣≤106 请注意可能需要使用int64,cin/cout可能超时。
样例解释:
第一次变化后,
A 0 6 3 4 6
B -12 -3 -5 -9
B=B−S⋅∣Ai−1−Ai∣,B=B+T⋅∣Ai−1−Ai∣这两个公式选哪个取决于Ai−1−Ai是否大于零,因此我们很容易想到使用预处理将数组A变为差分数组,这样A中的每个元素就代表Ai−1−Ai;
再观察B,我们可以分配一个数组来记录B的值
最后要输出的答案就是数组B的最后一个元素。通过观察公式B=B−S⋅∣Ai−1−Ai∣,B=B+T⋅∣Ai−1−Ai∣,发现第Bi由前一个元素Bi-1加上T⋅∣Ai−1−Ai∣或减去S⋅∣Ai−1−Ai∣,即数组B的最后一个元素等于0一直累加T⋅∣Ai−1−Ai∣或减去S⋅∣Ai−1−Ai∣得到。因此我们可让数组B仅记录S⋅∣Ai−1−Ai∣和T⋅∣Ai−1−Ai∣,这样,
每次对于一个区间的唱功值的改变,不会导致区间内的值相对大小的改变。
因此对于B值,我们每次只需要维护X、Y两个节点上的变更就好了。
核心代码如下:
这里的arr1就是上述的数组B
while (q--) {
scanf("%d%d%d", &x, &y, &z); // 从输入中读取x、y、z的值
arr[x] += z; // 将arr[x]增加z
arr[y + 1] -= z; // 将arr[y + 1]减去z,用于后续计算差分数组
ans -= arr1[x]; // 减去旧的arr1[x]值
if (y + 1 <= n)
ans -= arr1[y + 1]; // 如果y + 1不越界,则减去旧的arr1[y + 1]值
// 根据arr[x]的正负更新arr1[x]的值
if (arr[x] > 0) {
arr1[x] = -S * arr[x]; // 当arr[x]大于0时,arr1[x]等于-S乘以arr[x]
}
else {
arr1[x] = T * (-arr[x]); // 当arr[x]小于等于0时,arr1[x]等于T乘以负的arr[x]
}
// 根据arr[y + 1]的正负更新arr1[y + 1]的值
if (arr[y + 1] > 0) {
arr1[y + 1] = -S * arr[y + 1]; // 当arr[y + 1]大于0时,arr1[y + 1]等于-S乘以arr[y + 1]
}
else {
arr1[y + 1] = T * (-arr[y + 1]); // 当arr[y + 1]小于等于0时,arr1[y + 1]等于T乘以负的arr[y + 1]
}
ans += arr1[x]; // 加上新的arr1[x]值
if (y + 1 <= n)
ans += arr1[y + 1]; // 如果y + 1不越界,则加上新的arr1[y + 1]值
printf("%lld\n", ans); // 输出当前的ans值
}
完整代码如下:
这里的arr就是上述数组A
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long LL;
const int N = 2e6 + 5;
LL arr[N];
LL arr1[N];
int n, q, S, T;
int main() {
scanf("%d%d%d%d", &n, &q, &S, &T);
for (int i = 0; i <= n; i++) {
scanf("%lld", &arr[i]);
}
for (int i = n; i > 0; i--) {
arr[i] = arr[i] - arr[i - 1];
}
LL ans = 0;
for (int i = 1; i <= n; i++) {
if (arr[i] > 0) {
arr1[i] = - S * arr[i];
}
else {
arr1[i] = + T * (-arr[i]);
}
ans += arr1[i];
}
int x, y, z;
while (q--) {
scanf("%d%d%d", &x, &y, &z);
arr[x] += z;
arr[y + 1] -= z;
ans -= arr1[x];
if (y + 1 <= n)
ans -= arr1[y + 1];
if (arr[x] > 0) {
arr1[x] = -S * arr[x];
}
else {
arr1[x] = T * (-arr[x]);
}
if (arr[y + 1] > 0) {
arr1[y + 1] = -S * arr[y + 1];
}
else {
arr1[y + 1] = T * (-arr[y + 1]);
}
ans += arr1[x];
if (y + 1 <= n)
ans += arr1[y + 1];
printf("%lld\n", ans);
}
return 0;
}