题意:给定n个数据,每个数据包括一个年份和当年的降雨量,然后进行m次询问,每次询问给出两个年份Y,X,询问的内容是“X年是自Y年以来降雨量最多的”,你需要回答这句话是“必真”、“必假”还是“有可能”。“X年是自Y年以来降雨量最多的”的定义是X年的降雨量不超过Y年,且对于任意Y < Z < X,Z年的降雨量严格小于X年。
题解
这个题最大的难点在于如何分类讨论,而分类讨论的原因在于某些年份的信息不知道,并且不同位置的情况还不同。
本题还有不少坑点,比如询问的两个年份并不保证Y <= X,也就是说可能会出现Y > X的情况,这样肯定是“必假”的;还有就是分类讨论时不同情况选择的区间也不同。
在处理信息时,我是用了一个pos数组将年份存下来,由于所给的年份是按顺序给出的,所以询问时可以利用二分查找找到第一个不小于询问年份的年份下标,便于之后讨论。还需要用到区间最大值,这个用线段树维护一下即可。
既然不同位置年份信息缺失造成的结果不同,那么我们可以从这个角度入手进行讨论,我主要分了五种情况。以下内容中ul表示第一个不小于Y的年份下标,ur表示第一个不小于X的年份下标,数组a[i]代表年份下标为i的降雨量。
(1)Y > X,这种情况直接输出“false”。
(2)左端信息和右端信息都不确定,这种情况直接输出“maybe”,因为单单这两年的降雨量大小关系就未知,所以肯定不确定。
(3)左端信息确定,右端信息不确定,这个条件下只有两种结果,但要注意ul+1=ur的情况要单独拿出来,因为后面需要查询[ul + 1, ur - 1]区间的最大值,这种情况会导致左边界大于右边界,这种情况直接输出“maybe”,因为只有两个年份并且其中一个降雨量不确定。然后就是查询[ul + 1, ur - 1]区间的最大值,记为mx,如果mx大于等于a[ul],那mx肯定也大于等于a[ur],输出“false”;否则,输出“maybe”。
(4)左端信息不确定,右端信息确定,这种情况和(3)类似,但是要注意单独讨论的情况是ul=ur,然后查询的是[ul, ur - 1]区间的最大值(这里结合画图理解一下即可),其余的和(3)一样。
(5)左右端点信息都确定,首先判断两个端点的关系,如果a[ul] < a[ur],那么不满足条件,直接输出“false”;然后查询[ul + 1, ur - 1]的最大值,记为mx,如果mx大于等于a[ur],那么输出“false”;最后再看中间是否有缺失的年份,这里直接判断ur - ul是否等于X - Y即可,若相等,说明中间没有缺失年份,输出“true”,否则,输出“maybe”。
代码实现
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#define ll long long
using namespace std;
const int N = 5e4 + 50;
int n, m;
int tree[N << 2], a[N], pos[N];
void build(int u, int l, int r){
if(l == r){
tree[u] = a[l];
return;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
tree[u] = max(tree[u << 1], tree[u << 1 | 1]);
}
int query(int u, int l, int r, int ul, int ur){
if(ul <= l && ur >= r){
return tree[u];
}
int mid = (l + r) >> 1;
int ans = 0;
if(ul <= mid) ans = max(ans, query(u << 1, l, mid, ul, ur));
if(ur > mid) ans = max(ans, query(u << 1 | 1, mid + 1, r, ul , ur));
return ans;
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> pos[i] >> a[i];
build(1, 1, n);
cin >> m;
while(m--){
int l, r;
cin >> l >> r;
if(l > r){
cout << "false" << "\n";
continue;
}
int ul = lower_bound(pos + 1, pos + 1 + n, l) - pos;
int ur = lower_bound(pos + 1, pos + 1 + n, r) - pos;
int f1 = (pos[ul] == l), f2 = (pos[ur] == r);
if(!f1 && !f2){
cout << "maybe" << "\n";
continue;
}else if(f1 && !f2){
if(ul + 1 == ur){
cout << "maybe" << "\n";
continue;
}
int mx = query(1, 1, n, ul + 1, ur - 1);
if(mx >= a[ul]) cout << "false" << "\n";
else cout << "maybe" << "\n";
}else if(!f1 && f2){
if(ul == ur){
cout << "maybe" << "\n";
continue;
}
int mx = query(1, 1, n, ul, ur - 1);
if(mx >= a[ur]) cout << "false" << "\n";
else cout << "maybe" << "\n";
}else{
if(a[ul] < a[ur]){
cout << "false" << "\n";
continue;
}
int mx = query(1, 1, n, ul + 1, ur - 1);
if(mx >= a[ur]){
cout << "false" << "\n";
continue;
}
if(r - l == ur - ul) cout << "true" << "\n";
else cout << "maybe" << "\n";
}
}
return 0;
}