Loading

P8818 [CSP-S 2022] 策略游戏 题解

思路

题意:求一个特定矩形中每一行的最小值的最大值。

考虑分类讨论。

注意,由于 \(0\) 也需要考虑,所以下文中的正数和负数都包括了 \(0\)

  1. \(\text{a}\) 全部都是正的。

    由于 \(\text{a}\) 全部都是正的。

    那么无论小L选择什么,小Q总是会选择 \(\text{b}\) 序列中最小值。

    所以小L只需要从最大值(小Q选的是正数)和最小值(小Q选的是负数)中选一个就可以了。

  2. \(\text{a}\) 全部都是负的。

    与第一点类似。

    由于 \(\text{a}\) 全部都是负的。

    那么无论小L选择什么,小Q总是会选择 \(\text{b}\) 序列中最大值。

    所以小L只需要从最大值(小Q选的是负数)和最小值(小Q选的是正数)中选一个就可以了。

  3. \(\text{b}\) 全部都是正的

    由于我们已经考虑了上面两点,所以现在 \(\text{a}\) 序列必然是既有正数又有负数。

    那么小L一定会选择最大值,小Q也一定会选择最小值。

  4. \(\text{b}\) 全部都是负的

    和上面类似,其实就是反过来

    那么小L一定会选择最小值,小Q也一定会选择最大值。

  5. 没有特殊限制

    考虑到两个序列都是既有正数又有负数。

    那么就可以发现如果小L选择的是一个负数,那么小Q就会选择最大值;如果小L选择的是一个正数,那么小Q就会选择最小值。

    所以小L一定会选择最接近零的正数和负数,也就是正数最小值和负数最大值。

考虑一下上面需要求的东西。

\(\text{a}\) 序列最大最小值,\(\text{b}\) 序列最大最小值,\(\text{a}\) 序列正数最小值和 \(\text{a}\) 序列负数最大值。

这个开四颗线段树就可以了。

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

代码也比较好写。

Code

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

const int N = 100010;

int n , m , q , a[N] , b[N];
int s[N] , sum1[N] , sum2[N] , sum3[N] , sum4[N];

struct Node
{
    int l , r , minn , maxx;
};

struct Tree
{
    Node t[N * 4];
    inline void push_up(int p)
    {
        t[p].minn = min(t[p * 2].minn , t[p * 2 + 1].minn);
        t[p].maxx = max(t[p * 2].maxx , t[p * 2 + 1].maxx);
    }
    inline void build(int p , int l , int r)
    {
        t[p].l = l , t[p].r = r;
        if(l == r) return t[p].minn = t[p].maxx = s[l] , void();
        int mid = (l + r) / 2;
        build(p * 2 , l , mid);
        build(p * 2 + 1 , mid + 1 , r);
        push_up(p);
    }
    inline int ask1(int p , int l , int r)
    {
        if(l <= t[p].l && t[p].r <= r)
            return t[p].minn;
        int mid = (t[p].l + t[p].r) / 2 , ans = 1e9;
        if(l <= mid) ans = min(ans , ask1(p * 2 , l , r));
        if(r >  mid) ans = min(ans , ask1(p * 2 + 1 , l , r));
        return ans;
    }
    inline int ask2(int p , int l , int r)
    {
        if(l <= t[p].l && t[p].r <= r)
            return t[p].maxx;
        int mid = (t[p].l + t[p].r) / 2 , ans = -1e9;
        if(l <= mid) ans = max(ans , ask2(p * 2 , l , r));
        if(r >  mid) ans = max(ans , ask2(p * 2 + 1 , l , r));
        return ans;
    }
}t1 , t2 , t3 , t4;

//t1:a全
//t2:b全
//t3:a正
//t4:a负

inline int read()
{
    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
    return asd * qwe;
}

inline bool ask1(int l , int r) { return (sum1[r] - sum1[l - 1]) == (r - l + 1); }
inline bool ask2(int l , int r) { return (sum2[r] - sum2[l - 1]) == (r - l + 1); }
inline bool ask3(int l , int r) { return (sum3[r] - sum3[l - 1]) == (r - l + 1); }
inline bool ask4(int l , int r) { return (sum4[r] - sum4[l - 1]) == (r - l + 1); }

signed main()
{
    n = read() , m = read() , q = read();
    for(int i = 1;i <= n;i++)
        a[i] = read();
    for(int i = 1;i <= m;i++)
        b[i] = read();
    for(int i = 1;i <= n;i++)
        s[i] = a[i] , sum1[i] = sum1[i - 1] + (a[i] <= 0) , sum3[i] = sum3[i - 1] + (a[i] >= 0);
    t1.build(1 , 1 , n);
    for(int i = 1;i <= m;i++)
        s[i] = b[i] , sum2[i] = sum2[i - 1] + (b[i] <= 0) , sum4[i] = sum4[i - 1] + (b[i] >= 0);
    t2.build(1 , 1 , m);
    for(int i = 1;i <= n;i++) s[i] = (a[i] >= 0 ? a[i] : 1e9); t3.build(1 , 1 , n);
    for(int i = 1;i <= n;i++) s[i] = (a[i] < 0 ? a[i] : -1e9); t4.build(1 , 1 , n);
    for(int i = 1;i <= q;i++)
    {
        int l1 = read() , r1 = read() , l2 = read() , r2 = read();
        if(l1 > r1) swap(l1 , r2); if(l2 > r2) swap(l2 , r2);
        if(ask1(l1 , r1))
            cout << max(t1.ask2(1 , l1 , r1) * t2.ask2(1 , l2 , r2) , t1.ask1(1 , l1 , r1) * t2.ask2(1 , l2 , r2)) << endl;
        else if(ask3(l1 , r1))
            cout << max(t1.ask2(1 , l1 , r1) * t2.ask1(1 , l2 , r2) , t1.ask1(1 , l1 , r1) * t2.ask1(1 , l2 , r2)) << endl;
        else if(ask2(l2 , r2))
            cout << t1.ask1(1 , l1 , r1) * t2.ask2(1 , l2 , r2) << endl;
        else if(ask4(l2 , r2))
            cout << t1.ask2(1 , l1 , r1) * t2.ask1(1 , l2 , r2) << endl;
        else
            cout << max(t3.ask1(1 , l1 , r1) * t2.ask1(1 , l2 , r2) , t4.ask2(1 , l1 , r1) * t2.ask2(1 , l2 , r2)) << endl;
    }
    return 0;
}
posted @ 2022-11-01 14:35  JiaY19  阅读(201)  评论(0编辑  收藏  举报