NC20259 [SCOI2007]降雨量

发布时间 2023-04-25 22:51:18作者: 空白菌

题目链接

题目

题目描述

我们常常会说这样的话:“X年是自Y年以来降雨量最多的”。它的含义是X年的降雨量不超过Y年,且对于任意 Y<Z<X,Z年的降雨量严格小于X年。

例如2002,2003,2004和2005年的降雨量分别为4920,5901,2832和3890, 则可以说“2005年是自2003年以来最多的”,但不能说“2005年是自2002年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。

输入描述

输入仅一行包含一个正整数n,为已知的数据。
以下n行每行两个整数yi和ri,为年份和降雨量,按照年份从小 到大排列,即yi<yi+1。
下一行包含一个正整数m,为询问的次数。
以下m行每行包含两个数Y和X,即询问“X年是自Y年以来降雨量最多的。”这句话是必真、必假还是“有可能”。

输出描述

对于每一个询问,输出true,false或者maybe。

示例1

输入

6
2002 4920
2003 5901
2004 2832
2005 3890
2007 5609
2008 3024
5
2002 2005
2003 2005
2002 2007
2003 2007
2005 2008

输出

false
true
false
maybe
false

备注

100%的数据满足:\(1 \le n \le 50000, 1 \le m \le 10000, -10^9 \le y_i \le 10^9 , 1 \le r_i \le 10^9\)

题解

知识点:线段树,离散化。

数据范围显然需要离散化,然后就是普通的区间最大值查询,但是分类讨论年份左右端点会很麻烦:

  1. 左右是完全相等的,直接 true
  2. 左右都不存在,直接 maybe
  3. 左存在右不存在,如果已知的区间长度为 \(1\) 或除去右端点的区间最大值小于右端点值,则 maybe ;否则 false
  4. 左不存在右存在,如果已知的区间长度为 \(1\) 或除去左端点的区间最大值小于左端点值,则 maybe ;否则 false
  5. 左右都存在,若左端点值大于等于右端点值,且区间长度为1或2或除去左右端点的区间最大值小于右端点值,则继续判断;否则 false 。若满足条件,则若已知的区间长度等于实际年份跨度,则 true ;否则 maybe

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

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct T {
    int mx;
    static T e() { return { (int)-2e9 }; }
    friend T operator+(const T &a, const T &b) { return { max(a.mx,b.mx) }; }
};
template<class T>
class SegmentTree {
    int n;
    vector<T> node;

    T query(int rt, int l, int r, int x, int y) {
        if (r < x || y < l) return T::e();
        if (x <= l && r <= y) return node[rt];
        int mid = l + r >> 1;
        return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y);
    }

public:
    SegmentTree() {}
    SegmentTree(const vector<T> &src) { init(src); }
    void init(const vector<T> &src) {
        assert(src.size());
        n = src.size() - 1;
        node.assign(n << 2, T::e());
        function<void(int, int, int)> build = [&](int rt, int l, int r) {
            if (l == r) return node[rt] = src[l], void();
            int mid = l + r >> 1;
            build(rt << 1, l, mid);
            build(rt << 1 | 1, mid + 1, r);
            node[rt] = node[rt << 1] + node[rt << 1 | 1];
        };
        build(1, 1, n);
    }

    T query(int x, int y) { return query(1, 1, n, x, y); }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    vector<T> a(n + 1);
    vector<int> y_src(n + 1);
    for (int i = 1;i <= n;i++) {
        int y, r;
        cin >> y >> r;
        a[i] = { r };
        y_src[i] = y;
    }
    auto get = [&](int x)->int { return lower_bound(y_src.begin() + 1, y_src.end(), x) - y_src.begin(); };
    SegmentTree<T> sgt(a);
    int m;
    cin >> m;
    while (m--) {
        int l, r;
        cin >> l >> r;
        if (l > r) {
            cout << "false" << '\n';
            continue;
        }//* 题意不明
        if (l == r) {
            cout << "true" << '\n';
            continue;
        }
        int rkl = get(l), rkr = get(r);
        if (y_src[rkl] != l && y_src[rkr] != r) cout << "maybe" << '\n';
        else if (y_src[rkl] != l) {
            if (rkl == rkr || sgt.query(rkl, rkr - 1).mx < a[rkr].mx) cout << "maybe" << '\n';
            else cout << "false" << '\n';
        }
        else if (y_src[rkr] != r) {
            if (rkl + 1 == rkr || sgt.query(rkl + 1, rkr - 1).mx < a[rkl].mx) cout << "maybe" << '\n';
            else cout << "false" << '\n';
        }
        else if (a[rkl].mx >= a[rkr].mx && (rkl == rkr || rkl + 1 == rkr || sgt.query(rkl + 1, rkr - 1).mx < a[rkr].mx)) {
            if (r - l > rkr - rkl) cout << "maybe" << '\n';
            else cout << "true" << '\n';
        }
        else cout << "false" << '\n';
    }
    return 0;
}