CF1420C2 Pokémon Army (hard version) 题解

题目传送门

思路

考虑如何维护这个最大值。我们将区间 \([l, r]\) 分成 \([l, mid]\)\([mid + 1, r]\) 两个区间。我们发现如果前一个区间选了奇数个,那就应该减去后一个区间选的第一个元素;我们发现如果前一个区间选了偶数个,那就应该减去后一个区间选的第一个元素。那我们就可以分别维护选了奇数个/偶数个时的最大值/最小值。最后直接 push_up 即可。

最后只用实现单点修改和区间查询即可。

注意:当整个区间所选的长度为偶数时,可能是由左边区间选了奇数个 \(+\) 右边区间选了奇数个构成的。奇数同理。还需注意判 \(0\)

时间复杂度 \(\mathcal{O}(q \log n)\),可以通过本题。

代码

#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int N = 3e5 + 5;

int t, n, q;
int a[N];

struct seg_tree
{
	struct node
	{
		int l, r, maxnO, minnO, maxnE, minnE; 
	} tr[4 * N];
	node merge(node le, node ri) // 封装函数
	{
		node rt;
		rt.l = le.l, rt.r = ri.r; // 一定要转移 l 和 r
		rt.maxnO = max(le.maxnO - ri.minnE, le.maxnE + ri.maxnO);
		rt.minnO = min(le.minnO - ri.maxnE, le.minnE + ri.minnO);
		rt.maxnE = max(le.maxnE + ri.maxnE, le.maxnO - ri.minnO);
		rt.minnE = min(le.minnE + ri.minnE, le.minnO - ri.maxnO);
		rt.maxnE = max(rt.maxnE, 0ll), rt.minnE = min(rt.minnE, 0ll); // 注意判断 0 的情况
		return rt;
	}
	void push_up(int p)
	{
		tr[p] = merge(tr[p * 2], tr[p * 2 + 1]);
	}
	void build(int p, int l, int r)
	{
		tr[p] = {l, r, 0, (int)1e9, 0, (int)1e9};
		if (l == r)
		{
			tr[p].maxnO = tr[p].minnO = a[l];
			tr[p].maxnE = tr[p].minnE = 0;
			return;
		}
		int mid = (l + r) >> 1;
		build(p * 2, l, mid);
		build(p * 2 + 1, mid + 1, r);
		push_up(p);
	}
	void modify(int p, int l, int r, int k, int x)
	{
		if (l == r)
		{
			tr[p].maxnO = tr[p].minnO = x;
			tr[p].maxnE = tr[p].minnE = 0;
			return;
		}
		int mid = (l + r) >> 1;
		if (k <= mid) modify(p * 2, l, mid, k, x);
		else modify(p * 2 + 1, mid + 1, r, k, x);
		push_up(p);
	}
	node query(int p, int l, int r)
	{
		if (l <= tr[p].l && tr[p].r <= r) return tr[p];
		int mid = (tr[p].l + tr[p].r) >> 1;
		if (r <= mid) return query(p * 2, l, r);
		if (l > mid) return query(p * 2 + 1, l, r);
		return merge(query(p * 2, l, r), query(p * 2 + 1, l, r));
	}
} ST;

void solve()
{
	scanf("%lld%lld", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	ST.build(1, 1, n);
	seg_tree::node res = ST.query(1, 1, n);
	printf("%lld\n", max(res.maxnO, res.maxnE));
	while (q--)
	{
		int l, r;
		scanf("%lld%lld", &l, &r);
		swap(a[l], a[r]);
		ST.modify(1, 1, n, l, a[l]), ST.modify(1, 1, n, r, a[r]);
		seg_tree::node res = ST.query(1, 1, n);
		printf("%lld\n", max(res.maxnO, res.maxnE));
	}
}

signed main()
{
	scanf("%lld", &t);
	while (t--) solve();
	return 0;
}
posted @ 2026-02-01 16:24  lucasincyber  阅读(0)  评论(0)    收藏  举报