[CF2057D] Gifts Order 题解

似乎是一个很典的套路。
我们注意到一个区间成为答案时,最值一定在端点处
(如果不是,那么收缩一个一定更优)
于是我们就可以按照最值位置分类。

  • 最大值在区间左边,最小值在区间右边:答案就是 \((a_l + l) - (a_r + r)\)
  • 最大值在区间右边,最小值在区间左边:答案就是 \((a_r - r) - (a_l - l)\)

我们直接线段树维护 \(a_i + i\) 的最值和 \(a_i - i\) 的最值即可。

Q:算出来的和原式不等价,为什么是对的?
A:算的过程中相当于多包含了一些劣的情况,但是在取 \(\max\) 的过程中自动舍掉了,于是是对的。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Linf 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int> 
#define all(v) v.begin(), v.end()
using namespace std;

//#define filename "xxx" 
#define FileOperations() freopen(filename".in", "r", stdin), freopen(filename".out", "w", stdout)
#define multi_cases 1

namespace Traveller {
	const int N = 2e5+2;
	
	int n, q, a[N];
	
	struct data {
		int mx1, mx2, mn1, mn2;
		int ans;
		data() { }
		data(int a, int b, int c, int d, int e = 0) : mx1(a), mx2(b), mn1(c), mn2(d), ans(e) { }
	};
	data operator + (data a, data b) {
		int ans = max(max(a.ans, b.ans), max(a.mx1 - b.mn1, b.mx2 - a.mn2));
		int mx1 = max(a.mx1, b.mx1);
		int mx2 = max(a.mx2, b.mx2);
		int mn1 = min(a.mn1, b.mn1);
		int mn2 = min(a.mn2, b.mn2);
		return data(mx1, mx2, mn1, mn2, ans);
	}
	data operator + (data a, int b) {
		int mx1 = a.mx1 + b;
		int mx2 = a.mx2 + b;
		int mn1 = a.mn1 + b;
		int mn2 = a.mn2 + b;
		return data(mx1, mx2, mn1, mn2);
	}
	
	class SegmentTree {
		public:
			struct node {
				node *l, *r;
				data d;
				void up() { d = l->d + r->d; }
			} pool[N << 1], *tmp, *root;
			
			node *newnode() {
				tmp->l = tmp->r = NULL;
				tmp->d = data();
				return tmp++;
			}
			
			int l, r;
			
		public:
			void build(node *&p, int l, int r, int *a) {
				p = newnode();
				if(l == r) {
					p->d = data(a[l] + l, a[l] - l, a[l] + l, a[l] - l);
					return;
				}
				int mid = l + r >> 1;
				build(p->l, l, mid, a);
				build(p->r, mid+1, r, a);
				p->up();
			}
			void update(node *p, int l, int r, int idx, int v, int *a) {
				if(l == r) {
					p->d = p->d + (v - a[l]);
					a[l] = v;
					return;
				}
				int mid = l + r >> 1;
				if(mid >= idx) update(p->l, l, mid, idx, v, a);
				else update(p->r, mid+1, r, idx, v, a);
				p->up();
			}
			int query() { return root->d.ans; }
			
			void build(int l, int r, int *a) {
				tmp = pool;
				this->l = l, this->r = r;
				build(root, l, r, a);
			}
			void update(int idx, int v, int *a) { update(root, l, r, idx, v, a); }
	} tr;
	
	void main() {
		cin >> n >> q;
		for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		tr.build(1, n, a);
		printf("%d\n", tr.query());
		for(int i = 1, idx, v; i <= q; ++i) {
			scanf("%d%d", &idx, &v);
			tr.update(idx, v, a);
			printf("%d\n", tr.query());
		}
	}
}

signed main() {
#ifdef filename
	FileOperations();
#endif
	
	signed _ = 1;
#ifdef multi_cases
	scanf("%d", &_);
#endif
	while(_--) Traveller::main();
	return 0;
}


posted @ 2025-01-14 21:29  Water_M  阅读(28)  评论(0)    收藏  举报