题目
算法标签: S T ST ST表, 线段树
思路
可以求每一行的最小值, 第一个人从每一行最小值选择最大的一个, 但是行和列的数量是 1 0 5 10 ^ 5 105级别, 因此不能直接创建矩阵进行维护, 当第一个人选定某一行 x x x后确定了, 但是 B B B希望选择最小的, 需要考虑 A x A_x Ax的正负性, 如果 A x A_x Ax是正数, 需要在 B y B_y By中选择最小值, 目标值是 B m i n × A x B_{min} \times A_x Bmin×Ax, 对于第一个人来说, 如果想要求最大值, 还需要分析 B m i n B_{min} Bmin的正负性

总结来说对于如果 A x A_x Ax的所有取值都是正数数, 因为 A A A是绝顶聪明的, 是知道 B B B取最小值的, 因此对于 A A A来说最后的得分需要取决于 B m i n B_{min} Bmin的正负性
如果第一个人从负数里面选, 因为 A A A是决定聪明的, 因此是知道第二个人一定取值是 B m a x B_{max} Bmax, 还是取决于 B m a x B_{max} Bmax的正负性
将问题总结为
- 求 A A A的某个区间的非负整数的最小值
- 求 A A A的某个区间的非负整数的最大值
- 求 A A A的某个区间负数的最小值
- 求 A A A的某个区间负数的最大值
- 求 B B B的某个区间的最小值
- 求 B B B的某个区间的最大值
直接开 6 6 6个线段树或者 S T ST ST表求解
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 100010, INF = 2e9 + 10;
const LL LL_INF = 5e18;
int n, m, q;
int a[N], b[N];
struct Node {
int l, r, val;
} tr[6][N << 2];
int get(int u, int type) {
if (type == 0) return a[u] >= 0 ? a[u] : INF; // A中非负的最小值
if (type == 1) return a[u] >= 0 ? a[u] : -INF; // A中非负的最大值
if (type == 2) return a[u] < 0 ? a[u] : INF; // A中负数的最小值
if (type == 3) return a[u] < 0 ? a[u] : -INF; // A中负数的最大值
return b[u]; // B数组的值
}
void push_up(Node tr[], int u, int type) {
int l_val = tr[u << 1].val, r_val = tr[u << 1 | 1].val;
// 偶数求最小值
if (type % 2 == 0) tr[u].val = min(l_val, r_val);
// 奇数求最大值
else tr[u].val = max(l_val, r_val);
}
void build(Node tr[], int u, int l, int r, int type) {
tr[u] = {
l, r};
if (l == r) {
tr[u].val = get(r, type);
return;
}
int mid = l + r >> 1;
build(tr, u << 1, l, mid, type);
build(tr, u << 1 | 1, mid + 1, r, type);
push_up(tr, u, type);
}
int query(Node tr[], int u, int ql, int qr, int type) {
if (tr[u].l >= ql && tr[u].r <= qr) return tr[u].val;
int mid = tr[u].l + tr[u].r >> 1;
// 查询最小值
if (type % 2 == 0) {
int ans = INF;
if (ql <= mid) ans = min(ans, query(tr, u << 1, ql, qr, type));
if (qr > mid) ans = min(ans, query(tr, u << 1 | 1, ql, qr, type));
return ans;
}
// 查询最大值
int ans = -INF;
if (ql <= mid) ans = max(ans, query(tr, u << 1, ql, qr, type));
if (qr > mid) ans = max(ans, query(tr, u << 1 | 1, ql, qr, type));
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m >> q;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= m; ++i) cin >> b[i];
for (int i = 0; i < 4; ++i) build(tr[i], 1, 1, n, i);
for (int i = 4; i < 6; ++i) build(tr[i], 1, 1, m, i);
while (q--) {
int l1, r1, l2, r2;
cin >> l1 >> r1 >> l2 >> r2;
// 查询B数组的最小值和最大值
int y_min = query(tr[4], 1, l2, r2, 4);
int y_max = query(tr[5], 1, l2, r2, 5);
LL x, ans = -LL_INF;
// B的最小值非负时,A应选择最大的非负数
if (y_min >= 0) x = query(tr[1], 1, l1, r1, 1);
else x = query(tr[0], 1, l1, r1, 0);
if (abs(x) != INF) ans = max(ans, x * (LL)y_min);
// B的最大值非负时,A应选择最大的负数
if (y_max >= 0) x = query(tr[3], 1, l1, r1, 3);
else x = query(tr[2], 1, l1, r1, 2);
if (abs(x) != INF) ans = max(ans, x * (LL)y_max);
cout << ans << "\n";
}
return 0;
}


京公网安备 11010502036488号