P15687 [ICPC 2023 Jakarta R] Maximize The Value 题解

题目传送门

思路

首先,考虑转化题意。假设现在有 \(m\) 操作,每一个操作会将变量 \(v\) 增加 \(a_i\),现在需要执行一段连续的操作区间,使得 \(v\) 最大。

其实这道题的本质就是上面说的那个子问题。对于每一个操作区间 \((l, r, x)\),如果当前 \(k \in [l, r]\) 中,那这个操作对 \(a_k\) 的影响就为 \(x\),否则就为 \(0\)

这道题没有修改,很显然可以用一个扫描线把所有查询按 \(k\) 从小到大询问,这样就是线性的。考虑开一个 \([1, m]\) 的线段树,每一个叶子节点就代表第 \(i\) 个操作对于当前数的影响。那最后实际上就是求出 \([S, T]\) 中的最大子段和即可。这就是小白逛公园。最后用一个差分修改,如果 \(l_i = k\) 就把这个点的贡献加上,如果 \(r_i = k + 1\) 就把这个点的贡献减去。这样也就达成了 \((l, r, x)\) 的操作。时间复杂度 \(\mathcal{O}(m \log n)\)

代码

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

const int N = 1e5 + 5;

struct node
{
	int k, x;
};

struct query
{
	int k, l, r, id;
} q[N];

int n, m, t;
int ans[N];
vector<node> mo[N];

struct seg_tree
{
	struct node
	{
		int l, r, sum, maxL, maxR, maxn;
	} tr[4 * N];
	node merge(node x, node y)
	{
		node res;
		res.l = x.l, res.r = y.r;
		res.sum = x.sum + y.sum;
		res.maxL = max(x.maxL, x.sum + y.maxL);
		res.maxR = max(y.maxR, y.sum + x.maxR);
		res.maxn = max({x.maxn, y.maxn, x.maxR + y.maxL});
		return res;
	}
	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, 0, 0, 0};
		if (l == r) return;
		int mid = (l + r) >> 1;
		build(p * 2, l, mid);
		build(p * 2 + 1, mid + 1, r);
	}
	void modify(int p, int l, int r, int k, int x)
	{
		if (l == r)
		{
			tr[p].sum += x, tr[p].maxL += x, tr[p].maxR += x, tr[p].maxn += x;
			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);
		node res = merge(query(p * 2, l, r), query(p * 2 + 1, l, r));
		return res;
	}
} ST;

bool cmp(query x, query y)
{
	return x.k < y.k;
}

signed main()
{
	scanf("%lld%lld", &n, &m);
	for (int i = 1, l, r, x; i <= m; i++)
	{
		scanf("%lld%lld%lld", &l, &r, &x);
		mo[l].push_back({i, x});
		mo[r + 1].push_back({i, -x});
	}
	scanf("%lld", &t);
	for (int i = 1; i <= t; i++)
	{
		scanf("%lld%lld%lld", &q[i].k, &q[i].l, &q[i].r);
		q[i].id = i;
	}
	sort(q + 1, q + t + 1, cmp);
	ST.build(1, 1, m);
	for (int i = 1, j = 1; i <= n; i++)
	{
		for (node now : mo[i])
			ST.modify(1, 1, m, now.k, now.x);
		while (j <= t && q[j].k == i)
		{
			int res = ST.query(1, q[j].l, q[j].r).maxn;
			ans[q[j].id] = res;
			j++;
		}
	}
	for (int i = 1; i <= t; i++)
		printf("%lld\n", ans[i]);
	return 0;
}

写在最后:双倍经验 CF1906F

posted @ 2026-03-12 16:27  lucasincyber  阅读(7)  评论(0)    收藏  举报