洛谷9877 [EC Final 2021] Vacation 题解(线段树)

将数列按 \(c\) 分块,则一个查询 \([l,r]\) 的贡献由以下几部分组成:

  1. \([l,r]\) 之间的整块的最大子段和。

  2. \(l\) 到第一个整块之间的最大子段和。

  3. 最后一个整块到 \(r\) 的最大子段和。

  4. 整块与整块之间的跨边界的最大子段和。

  5. \(l\) 与第一个整块之间跨边界的最大子段和。

  6. 最后一个整块与 \(r\) 之间跨边界的最大子段和。

我们知道,整块内部的最大子段和是好维护的(小白逛公园),接下来考虑怎么维护跨边界的贡献。考虑设 \(f_i\) 表示当前块的前 \(i\) 个数之和,\(g_j\) 表示上一个块的后 \(j\) 个数之和,最后的答案就是 \(\max_{i+j\le c} f_i+g_j\)

像这种形式的 \((\max,+)\) 卷积,一个用线段树维护的方法是令 \(g'_x = g_{c-x}\),将答案转化为 \(\max_{i<j} f_i+g_j\)。这个东西是线段树可维护的,我们将 \(f\) 整体右移一位,将所求式子转为 \(\max_{i\le j} f_i+g_j\),然后每个节点维护对应区间的内的 \(\max f_i, \max g_i, \max_{i\le j} f_i+g_j\),在 pushup 的时候考虑当前的左儿子的 \(\max f\) 与右儿子的 \(\max g\) 相加是否更优即可。可以证明,这样维护是正确的。

维护这个 \((\max, +)\) 卷积的线段树还需要支持区间修改(因为我们每次改相当于是更新了 \(f\) 的一个后缀, \(g\) 的一个前缀),考虑标记与信息的合并。可以证明,一个区间 \(f_i'=f_i+v\),最终的答案也一定为 \(ans'=ans+v\)\(g_i\) 同理。

对于整块之间的答案,由于每次查询的时候可能会跨很多整块,所以我们在外面再开一个线段树,维护整块之间的答案 \(\max\) 即可。

对于散块的贡献,用左端点举例,相当于是有一部分 \(g\) 的后缀可用,其所有的 \(f\) 都可用,则我们可以令中间这个端点为 \(x\),统计 \([x, R']\) 的答案与 \(\max g\)\([L',x-1]\)\(\max f\),最后用 \(\max f+\max g\) 更新答案。右端点同理。

最终时间复杂度 \(O(n \log n)\)

const int MAXN = 2e5 + 5;
int n, m, c, a[MAXN];

struct _sgt_zdh {
	int N;

	struct _node {
		int sm, mx, lmx, rmx;
	};
	vector<_node> tr;

	void init(int _N) {
		N = _N;
		tr.resize(N * 4);
	}

	void pushup(int p) {
		tr[p].sm = tr[lson].sm + tr[rson].sm;
		tr[p].mx = max({tr[lson].mx, tr[rson].mx, tr[lson].rmx + tr[rson].lmx});
		tr[p].lmx = max(tr[lson].lmx, tr[lson].sm + tr[rson].lmx);
		tr[p].rmx = max(tr[rson].rmx, tr[rson].sm + tr[lson].rmx);
	}

	void modify(int p, int l, int r, int k, int v) {
		if (l == r) {
			tr[p].sm = tr[p].mx = tr[p].lmx = tr[p].rmx = v;
			return;
		}
		if (k <= mid) modify(lson, l, mid, k, v);
		else modify(rson, mid + 1, r, k, v);
		pushup(p);
	}

	auto query(int p, int l, int r, int L, int R) {
		if (L <= l && r <= R) return tr[p];
		auto merge = [](_node ls, _node rs) {
			_node ret;
			ret.sm = ls.sm + rs.sm;
			ret.mx = max({ls.mx, rs.mx, ls.rmx + rs.lmx});
			ret.lmx = max(ls.lmx, ls.sm + rs.lmx);
			ret.rmx = max(rs.rmx, rs.sm + ls.rmx);
			return ret;
		};
		_node ret = {0, INT_MIN, INT_MIN, INT_MIN};
		if (L <= mid) ret = query(lson, l, mid, L, R);
		if (mid < R) ret = merge(ret, query(rson, mid + 1, r, L, R));
		return ret;
	}
};

struct _sgt_conv {
	int N;

	struct _node {
		int f, g, sm;
		int tagf, tagg;
	};
	vector<_node> tr;

	void pushup(int p) {
		tr[p].f = max(tr[lson].f, tr[rson].f);
		tr[p].g = max(tr[lson].g, tr[rson].g);
		tr[p].sm = max({tr[lson].sm, tr[rson].sm, tr[lson].f + tr[rson].g});
	}

	void init(int _N) {
		N = _N;
		tr.resize(N * 4);
	}

	void addtagf(int p, int v) {
		tr[p].tagf += v;
		tr[p].sm += v;
		tr[p].f += v;
	}

	void addtagg(int p, int v) {
		tr[p].tagg += v;
		tr[p].sm += v;
		tr[p].g += v;
	}

	void pushdown(int p) {
		if (tr[p].tagf) {
			addtagf(lson, tr[p].tagf);
			addtagf(rson, tr[p].tagf);
			tr[p].tagf = 0;
		}
		if (tr[p].tagg) {
			addtagg(lson, tr[p].tagg);
			addtagg(rson, tr[p].tagg);
			tr[p].tagg = 0;
		}
	}

	void modifyf(int p, int l, int r, int L, int R, int v) {
		if (L <= l && r <= R) return addtagf(p, v);
		pushdown(p);
		if (L <= mid) modifyf(lson, l, mid, L, R, v);
		if (mid < R) modifyf(rson, mid + 1, r, L, R, v);
		pushup(p);
	}

	void modifyg(int p, int l, int r, int L, int R, int v) {
		if (L <= l && r <= R) return addtagg(p, v);
		pushdown(p);
		if (L <= mid) modifyg(lson, l, mid, L, R, v);
		if (mid < R) modifyg(rson, mid + 1, r, L, R, v);
		pushup(p);
	}

	auto query(int p, int l, int r, int L, int R) {
		if (L > R) return (_node){INT_MIN, INT_MIN, INT_MIN};
		if (L <= l && r <= R) return tr[p];
		auto merge = [](_node u, _node v) {
			_node ret;
			ret.f = max(u.f, v.f);
			ret.g = max(u.g, v.g);
			ret.sm = max({u.sm, v.sm, u.f + v.g});
			return ret;
		};
		pushdown(p);
		_node res = {INT_MIN, INT_MIN, INT_MIN};
		if (L <= mid) res = query(lson, l, mid, L, R);
		if (mid < R) res = merge(res, query(rson, mid + 1, r, L, R));
		return res;
	}
};

struct _sgt_max {
	int N;

	struct _node {
		int mx;
	};
	vector<_node> tr;

	void pushup(int p) {
		tr[p].mx = max(tr[lson].mx, tr[rson].mx);
	}

	void init(int _N) {
		N = _N;
		tr.resize(N * 4);
	}

	void modify(int p, int l, int r, int k, int v) {
		if (l == r) return tr[p].mx = v, void();
		if (k <= mid) modify(lson, l, mid, k, v);
		else modify(rson, mid + 1, r, k, v);
		pushup(p);
	}

	int query(int p, int l, int r, int L, int R) {
		if (L <= l && r <= R) return tr[p].mx;
		int res = INT_MIN;
		if (L <= mid) res = max(res, query(lson, l, mid, L, R));
		if (mid < R) res = max(res, query(rson, mid + 1, r, L, R));
		return res;
	}
} tans;

int L[MAXN], R[MAXN], bel[MAXN];
vector<_sgt_zdh> tzdh;
vector<_sgt_conv> tconv;

void work() {
	cin >> n >> m >> c;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	int B = (n + c - 1) / c;
	for (int i = 1; i <= B; ++i) {
		L[i] = (i - 1) * c + 1;
		R[i] = min(n, i * c);
	}
	for (int i = 1; i <= B; ++i) {
		for (int j = L[i]; j <= R[i]; ++j) {
			bel[j] = i;
		}
	}
	tzdh.resize(B + 1);
	for (int i = 1; i <= B; ++i) {
		tzdh[i].init(R[i] - L[i] + 1);
		for (int j = L[i]; j <= R[i]; ++j) {
			tzdh[i].modify(1, 1, R[i] - L[i] + 1, j - L[i] + 1, a[j]);
		}
	}
	tconv.resize(B + 1);
	for (int i = 1; i <= B; ++i) {
		tconv[i].init(c);
		for (int j = 1; j <= R[i] - L[i] + 1; ++j) {
			int x = L[i] + j - 1;
			tconv[i].modifyf(1, 0, c, j, c, a[x]);
		}
		if (i > 1) {
			for (int j = 1; j <= R[i - 1] - L[i - 1] + 1; ++j) {
				int x = L[i - 1] + j - 1;
				if (j != 1) tconv[i].modifyg(1, 0, c, 0, j - 1, a[x]);
			}
		}
	}
	tans.init(2 * B);
	for (int i = 1; i <= B; ++i) {
		tans.modify(1, 1, 2 * B, 2 * i, tzdh[i].tr[1].mx);
		if (i > 1) {
			tans.modify(1, 1, 2 * B, 2 * i - 1, tconv[i].tr[1].sm);
		}
	}
	while (m--) {
		int op; cin >> op;
		if (op == 1) {
			int x, y; cin >> x >> y;
			tzdh[bel[x]].modify(1, 1, tzdh[bel[x]].N, x - L[bel[x]] + 1, y);
			tans.modify(1, 1, 2 * B, 2 * bel[x], tzdh[bel[x]].tr[1].mx);
			tconv[bel[x]].modifyf(1, 0, c, x - L[bel[x]] + 1, c, y - a[x]);
			tans.modify(1, 1, 2 * B, 2 * bel[x] - 1, tconv[bel[x]].tr[1].sm);
			if (bel[x] != B) {
				if (x != L[bel[x]]) tconv[bel[x] + 1].modifyg(1, 0, c, 0, x - L[bel[x]], y - a[x]);
				tans.modify(1, 1, 2 * B, 2 * bel[x] + 1, tconv[bel[x] + 1].tr[1].sm);
			}
			a[x] = y;
		} else {
			int l, r; cin >> l >> r;
			int lx = l - L[bel[l]] + 1, rx = r - L[bel[r]] + 1;
			if (bel[l] == bel[r]) {
				cout << max(tzdh[bel[l]].query(1, 1, tzdh[bel[l]].N, lx, rx).mx, 0ll) << endl;
				continue;
			}
			int ans = 0;
			if (bel[l] + 1 < bel[r]) {
				ans = max(ans, tans.query(1, 1, 2 * B, (bel[l] + 1) * 2, (bel[r] - 1) * 2));
				auto resR = tconv[bel[l] + 1].query(1, 0, c, lx - 1, c);
				auto resL = tconv[bel[l] + 1].query(1, 0, c, 0, lx - 2);
				ans = max(ans, max(resR.sm, resL.f + resR.g));
				resL = tconv[bel[r]].query(1, 0, c, 0, rx);
				resR = tconv[bel[r]].query(1, 0, c, rx + 1, c);
				ans = max(ans, max(resL.sm, resL.f + resR.g));
			} else {
				auto resL = tconv[bel[r]].query(1, 0, c, 0, min(rx, lx - 2));
				auto resR = tconv[bel[r]].query(1, 0, c, max(rx + 1, lx - 1), c);
				ans = max(ans, resR.g + resL.f);
				if (rx >= lx - 1) {
					auto res = tconv[bel[r]].query(1, 0, c, lx - 1, rx);
					ans = max(ans, max({res.sm, res.g + resL.f, resR.g + res.f}));
				}
			}
			ans = max(ans, tzdh[bel[l]].query(1, 1, tzdh[bel[l]].N, l - L[bel[l]] + 1, tzdh[bel[l]].N).mx);
			ans = max(ans, tzdh[bel[r]].query(1, 1, tzdh[bel[r]].N, 1, r - L[bel[r]] + 1).mx);
			cout << ans << endl;
		}
	}
}
posted @ 2025-10-21 16:31  小蛐蛐awa  阅读(11)  评论(0)    收藏  举报