【】plusplus

【链接】h在这里写链接


【题意】


给你一个长度为n的a数组.
再给你一个相同长度的b数组,一开始全为0.
给你m个操作,每个操作li,ri.
表示把b数组的li..ri这一段的元素全都加上di.
让你找最小的k(k>=0),使得第k次操作过后,b数组变成了a数组.
(不存在就输出-1)
n,m<=10^6,li,ri<=n,di<=10^9,a[i]<=10^18



【题解】


设c[i]表示a数组第i个位置与第i-1个位置的差。
c[1] = a[1],c[2] = a[2]-a[1],c[3] = a[3]-a[2]....
则这个c[i]数组,实际上表明的是,b数组,i这个位置比前一个位置要多加上的数字大小
统计c数组不为0的个数cnt.
显然,当cnt变成0了。则满足题目要求了。
在把li..ri进行操作的时候,li+1..ri这个区间里面的c数组是不会发生改变的。因为它们是同增的.
只需改变li和ri+1位置的c数组就好.
然后改变cnt.
直到cnt变成0就好.
复杂度是O(N)的。

【错的次数】


0

【反思】


关键点就是构造出这个c数组。

【代码】

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;

int n, m;
int a[N + 10];

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = n; i >= 1; i--)
		a[i] = a[i] - a[i - 1];
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (a[i])
			cnt++;
	if (cnt == 0)
		return puts("0"), 0;
	for (int i = 1; i <= m; i++) {
		int l, r, x;
		scanf("%d%d%d", &l, &r, &x);
		r++;
		if (a[l] == 0 && a[l] - x != 0) cnt++;
		if (a[l] != 0 && a[l] - x == 0) cnt--;
		if (r <= n && a[r] == 0 && a[r] + x != 0) cnt++;
		if (r <= n && a[r] != 0 && a[r] + x == 0) cnt--;
		a[l] -= x, a[r] += x;
		if (cnt == 0) {
			printf("%d\n", i);
			return 0;
		}
	}
	puts("-1");
	return 0;
}


posted @ 2017-10-04 18:44  AWCXV  阅读(121)  评论(0编辑  收藏  举报