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;
}

posted @ 2023-06-06 17:37  Landnig_on_Mars  阅读(25)  评论(0编辑  收藏  举报  来源