[SP2916 GSS5] Can you answer these queries V(线段树 + 细节) | 错题本

文章目录

题目

[SP2916 GSS5] Can you answer these queries V

分析

先考虑两个区间不相交的情况:只需要求 [ l 1 , r 1 ] [l_1, r_1] [l1,r1] 的前缀和最小值和 [ l 2 , r 2 ] [l_2, r_2] [l2,r2] 的前缀和最大值,相减就是答案。再考虑两个区间相交的情况,相交部分用 GSS1 解决即可,未相交部分考虑两种情况:左端点在 [ l 1 , l 2 ] [l_1, l_2] [l1,l2] 右端点在 ( l 2 , r 2 ] (l_2, r_2] (l2,r2];左端点在 [ l 1 , r 1 ] [l_1, r_1] [l1,r1] 右端点在 ( r 1 , r 2 ] (r_1, r_2] (r1,r2]。最大值支持重复计算,所以不管那么多全部取最大值即可。

代码

注意区间端点先处理一下排除不合法区间(例如 l 2 < l 1 l_2 < l_1 l2<l1)。

#include <bits/stdc++.h>

int Read() {
	int x = 0; bool f = false; char c = getchar();
	while (c < '0' || c > '9')
		f |= c == '-', c = getchar();
	while (c >= '0' && c <= '9')
		x = x * 10 + (c ^ 48), c = getchar();
	return f ? -x : x;
}

const int MAXN = 10000;

#define lch (u << 1)
#define rch (u << 1 | 1)

int N, Q;
int A[MAXN + 5], S[MAXN + 5];

struct Node {
	int lft, rgt, mid, tot, mx, mn;

	Node operator + (const Node &other) const {
		return {
			std::max(lft, tot + other.lft),
			std::max(other.rgt, other.tot + rgt),
			std::max(std::max(mid, other.mid), rgt + other.lft),
			tot + other.tot,
			std::max(mx, other.mx), std::min(mn, other.mn)
		};
	}
} T[MAXN * 4 + 5];

void Build(const int &u, const int &l, const int &r) {
	if (l == r) {
		T[u].lft = T[u].rgt = T[u].mid = T[u].tot = A[l];
		T[u].mx = T[u].mn = S[l];
		return;
	}
	int mid = (l + r) >> 1;
	Build(lch, l, mid);
	Build(rch, mid + 1, r);
	T[u] = T[lch] + T[rch];
}

Node Query(const int &u ,const int &l, const int &r, const int &lft, const int &rgt) {
	if (lft <= l && r <= rgt)
		return T[u];
	int mid = (l + r) >> 1;
	if (rgt <= mid) return Query(lch, l, mid, lft, rgt);
	if (lft >= mid + 1) return Query(rch, mid + 1, r, lft, rgt);
	return Query(lch, l, mid, lft, rgt) + Query(rch, mid + 1, r, lft, rgt);
}

int main() {
	int T = Read();
	while (T--) {
		N = Read();
		for (int i = 1; i <= N; i++)
			S[i] = S[i - 1] + (A[i] = Read());
		Build(1, 0, N);
		Q = Read();
		while (Q--) {
			int l1 = Read(), r1 = Read(), l2 = Read(), r2 = Read();
			l2 = std::max(l2, l1), r1 = std::min(r1, r2);
			if (l2 > r1)
				printf("%d\n", Query(1, 0, N, l2, r2).mx - Query(1, 0, N, l1 - 1, r1 - 1).mn);
			else {
				int res1 = Query(1, 0, N, r1, r2).mx - Query(1, 0, N, l1 - 1, r1 - 1).mn;
				int res2 = Query(1, 0, N, l2, r2).mx - Query(1, 0, N, l1 - 1, l2 - 1).mn;
				int res3 = Query(1, 0, N, l2, r1).mid;
				printf("%d\n", std::max(res1, std::max(res2, res3)));
			}
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值