专栏文章

题解:P7402 [COCI 2020/2021 #5] Sjeckanje

P7402题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@minr8pta
此快照首次捕获于
2025/12/02 07:02
3 个月前
此快照最后确认于
2025/12/02 07:02
3 个月前
查看原文

Solution

CF484D 的带修版本。
关键观察:最优方案里,划分完的每个区间一定是单调的。证明是显然的。那么,划分点一定在每个波峰和波谷。
考虑原数组的差分序列,则单调区间就转化成了同号区间,答案就是区间和的绝对值。对于修改,我们要做的是单点修改和查询全局答案。
考虑线段树,pushup 如何合并两个区间?若两个子区间合起来是单调的,答案显然就是他们的和;若不是,就要讨论一下波峰和波谷选不选了。于是我们定义 sumx, 0/1, 0/1\text{sum}_{x, \space 0/1, \space 0/1},表示区间 xx 左端点不选或选,右端点不选或选的答案,合并的时候讨论一下左儿子的右端点和右儿子的左端点选不选,取个 max\max 就行了。
注意一个 corner case:n=1n = 1 时如果写 O(n)O(n) 建树会 RE,原因是会构建一个 [2,1][2, 1] 的区间。特判一下就行。

Code

CPP
// Problem: P7402 [COCI 2020/2021 #5] Sjeckanje
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7402
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long 
#define pii pair<int,int>
#define pb push_back
#define endl '\n'
#define rep(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++)
#define per(i, a, b) for(int (i) = (a); (i) >= (b); (i) --)
#define ls x << 1
#define rs x << 1 | 1

using namespace std;

const int maxn = 2e5 + 5 ;

int n, q, a[maxn] ; 
ll d[maxn] ;

struct sgt {
	#define maxn (maxn << 2)
	int l[maxn], r[maxn] ;
	ll sum[maxn][2][2] ;
	#undef maxn
	void pushup(int x, int mid) {
		rep(i, 0, 1) {
			rep(j, 0, 1) {
				if((d[mid] >= 0 && d[mid + 1] >= 0) || (d[mid] <= 0 && d[mid + 1] <= 0)) {
					sum[x][i][j] = sum[ls][i][1] + sum[rs][1][j] ;
				}
				else {
					sum[x][i][j] = max(sum[ls][i][0] + sum[rs][1][j], sum[ls][i][1] + sum[rs][0][j]) ;
				}
			}
		}
	}
	void build(int x, int L, int R) {
		l[x] = L, r[x] = R ;
		if(l[x] == r[x]) {
			sum[x][1][1] = llabs(d[L]) ;
			return ;
		}
		int mid = (L + R) >> 1 ; 
		build(ls, L, mid) ;
		build(rs, mid + 1, R) ;
		pushup(x, mid) ;
	}
	void add(int x, int pos) {
		if(l[x] == r[x]) {
			sum[x][1][1] = llabs(d[l[x]]) ;
			return ;
		}
		int mid = (l[x] + r[x]) >> 1 ;
		if(pos <= mid) add(ls, pos) ;
		if(pos > mid) add(rs, pos) ;
		pushup(x, mid) ;
	}
} t ;

void solve(){
	cin >> n >> q ;
	rep(i, 1, n) {
		cin >> a[i] ;
		d[i] = a[i] - a[i - 1] ;
	}
	if(n == 1) {
		while(q -- ) {
			int l, r, x ; cin >> l >> r >> x ;
			cout << 0 << endl ;
		}
		return ;
	}
	t.build(1, 2, n) ;
	while(q -- ) {
		int l, r, x ; cin >> l >> r >> x ;
		if(l >= 2) {
			d[l] += x ;
			t.add(1, l) ;
		}
		if(r + 1 <= n) {
			d[r + 1] -= x ;
			t.add(1, r + 1) ;
		}
		cout << t.sum[1][1][1] << endl ;
	}
	return ;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int T = 1 ; 
//	cin >> T ;
	while(T -- ){
		solve() ;
	}
	return 0 ;
} 

评论

2 条评论,欢迎与作者交流。

正在加载评论...