NC20259 [SCOI2007]降雨量
题目
题目描述
我们常常会说这样的话:“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\)
题解
知识点:线段树,离散化。
数据范围显然需要离散化,然后就是普通的区间最大值查询,但是分类讨论年份左右端点会很麻烦:
- 左右是完全相等的,直接
true
。 - 左右都不存在,直接
maybe
。 - 左存在右不存在,如果已知的区间长度为 \(1\) 或除去右端点的区间最大值小于右端点值,则
maybe
;否则false
。 - 左不存在右存在,如果已知的区间长度为 \(1\) 或除去左端点的区间最大值小于左端点值,则
maybe
;否则false
。 - 左右都存在,若左端点值大于等于右端点值,且区间长度为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;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17354226.html