1. 程式人生 > 實用技巧 >Three Sequences(差分序列構造)

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