Three Sequences(差分序列构造)

题目链接:D. Three Sequences

题意:给你一个长度为n的序列a,你要把每一个ai拆成bi + ci,形成两个长度为n的序列b和c,并且要保证b序列单调非递减,c序列单调非递增,然后进行m次操作,每次操作使得a序列的[l, r]区间增加k,问每次操作之后b,c序列的最大值最小是多少

Input

第一行输入一个n(1 <= n <= 1e5),代表有n个数,第二行输入n个数表示a序列(-1e9 <= ai <= 1e9),第三行输入m(1 <= m <= 1e5)表示有m次操作,然后m行,每行输入l, r, k(1 <= l <= r <= n, -1e9 <= k <= 1e9)表示a序列[l, r]区间增加k。
Output

首先输出未操作之前的b,c序列的最大值最小是多少,然后每次操作之后输出b,c序列的最大值最小是多少。

Sample Input

4
2 -1 7 3
2
2 4 -3
3 4 2

Sample Output

5
5
6

思路:

由于b序列是非递减的,c序列是非递增的,那么题目实际上让我们求的就是max(bn, c1)的最小值。

直接构造b,c序列无从下手,那么我们考虑构造b,c序列的差分数组,也就是把a的差分数组拆成b,c的差分数组。记a的差分数组为da。

考虑到b数组要非递增,c数组要非递减,所以b数组差分数组中的每个值都>=0,c数组差分数组中的每个值都<=0,那么对于dai,如果dai>0那么他一定要全都分到b的差分数组中,否则会使bn更大,如果dai<0那么他一定要全都分到c的差分数组中,否则也会使bn更大。所以,对于a的差分数组,正差分一定要分到b的差分数组中,负差分一定要分到c的差分数组中。

差分序列确定后,max(bn, c1)的值只由b1,c1决定,记a差分数组的正差分之和为sum。

那么bn = b1 + sum, 要使得max(bn, c1)最小,那么需要使bn = c1,即b1 + sum = c1,又b1 + c1 = a1,所以b1 = (a1 - sum) / 2,c1 = a1 - b1,答案为max(b1 + sum, c1)

所以最终答案只与b1,c1,sum有关,因此下面进行区间操作时,对差分序列只改变了两个值,对sum做维护即可O(1)出答案。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;

typedef long long ll;

const int N = 100010;

int n, m;
ll a[N], b[N], k;

int main() {
    int l, r;
    scanf("%d", &n);
    ll sum = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        b[i] = a[i] - a[i - 1];
        if(b[i] > 0 && i > 1) sum += b[i];
    }
    ll x = (b[1] - sum) / 2;
    ll y = b[1] - x;
    ll ans = max(x + sum, y);
    printf("%lld\n", ans);
    //cout << "++" << sum << endl;
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%d %d %lld", &l, &r, &k);
        ll now1 = b[l] + k;
        if(l != 1) {
            if(b[l] > 0 && now1 <= 0) {
                sum -= b[l];
            } else if(b[l] <= 0 && now1 > 0) {
                sum += now1;
            } else if(b[l] >= 0 && now1 >= 0) {
                sum += k;
            }
        }
        b[l] = now1;
        ll now2 = b[r + 1] - k;
        if(r != n) {
            if(b[r + 1] > 0 && now2 <= 0) {
                sum -= b[r + 1];
            } else if(b[r + 1] <= 0 && now2 > 0) {
                sum += now2;
            } else if(b[r + 1] >= 0 && now2 >= 0) {
                sum -= k;
            }
        }
        b[r + 1] = now2;
        //cout << sum << "---" << endl;
        x = (b[1] - sum) / 2;
        y = b[1] - x;
        ans = max(x + sum, y);
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

posted @ 2020-11-04 20:33  LightandDust  阅读(158)  评论(0)    收藏  举报