题目描述
我们常常会说这样的话:“X 年是自 Y 年以来降雨量最多的”。它的含义是 X 年的降雨量不超过 Y 年,且对于任意 Y<Z<X,Z 年的降雨量严格小于 X 年。例如 2002,2003,2004 和 2005 年的降雨量分别为 4920,5901,2832 和 3890,则可以说“2005 年是自 2003 年以来最多的”,但不能说“2005 年是自 2002 年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。
输入格式
输入仅一行包含一个正整数 nnn,为已知的数据。以下 n 行每行两个整数 y i y_i yi和 r i r_i ri,为年份和降雨量,按照年份从小到大排列,即 y i < y i + 1 y_i<y_{i+1} yi<yi+1。下一行包含一个正整数 m,为询问的次数。以下 m 行每行包含两个数 Y 和 X ,即询问“X 年是自 Y 年以来降雨量最多的。”这句话是必真、必假还是“有可能”。
样例
6
2002 4920
2003 5901
2004 2832
2005 3890
2007 5609
2008 3024
5
2002 2005
2003 2005
2002 2007
2003 2007
2005 2008
输出格式
对于每一个询问,输出true,false或者maybe
false
true
false
maybe
false
算法简述
用线段树维护年份区间的最大值,并同时记录区间的连续性,查询即可
细节
如何判断区间连续?
若连续,则左区间连续,右区间连续,且左区间右端点和右区间左端点差为1
否则不连续
线段树
排序,用下标建树
代码实现
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<climits>
#include<cctype>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<string>
#include<stack>
#include<string>
#include<string.h>
using namespace std;
#pragma GCC optimize(2)
#pragma warning(disable:4996)
using namespace std;
const int maxn = 60000;
struct node
{
int y, v;
}a[maxn];
struct ans
{
int flg, v;//flg标记这个节点维护的区间是否连续,v表示这个区间的最大降水量
};
ans maxr[maxn << 2];
int n;
void build(int x, int l, int r)
{
if (l == r)
{
maxr[x] = { 1,a[l].v };
return;
}
int mid = l + (r - l) / 2;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
maxr[x].v = max(maxr[x << 1].v, maxr[x << 1 | 1].v);
if (a[mid + 1].y - a[mid].y == 1 && maxr[x << 1].flg && maxr[x << 1 | 1].flg)//如果左右节点区间连续,且左区间连续右区间也连续,x节点维护的区间就是连续的
{
maxr[x].flg = 1;
}
else
{
maxr[x].flg = 0;
}
}
ans query(int x, int l, int r, int ql, int qr)//询问y[ql]到y[qr]年的最大值
{
if (l >= ql && r <= qr)
{
return maxr[x];
}
int mid = (l + r) >> 1;
ans res, tmp;
res.flg = 1;
res.v = INT_MIN;
bool f1=0, f2=0;
if (ql <= mid)
{
f1 = 1;
tmp = query(x << 1, l, mid, ql, qr);
res.v = max(res.v, tmp.v);
if (!tmp.flg)//如果左右有一部分不连续,那么这个返回指就不连续
{
res.flg = 0;
}
}
if (qr > mid)
{
f2 = 1;
tmp = query(x << 1 | 1, mid + 1, r, ql, qr);
res.v = max(res.v, tmp.v);
if (!tmp.flg)
{
res.flg = 0;
}
}
if (f1 && f2)
{
if (a[mid + 1].y - a[mid].y != 1)
{
res.flg = 0;
}
}
return res;
}
inline int search_upper(int x)//搜索大于等于x年的下标
{
int l = 1, r = n, mid, res = INT_MIN;
while (l <= r)
{
mid = (l + r) >> 1;
if (a[mid].y == x)
{
return mid;
}
if (a[mid].y > x)
{
res = mid;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return res;
}
inline int search_lower(int x)//搜索一个小于等于x年的下标
{
int l = 1, r = n, mid, res = INT_MIN;
while (l <= r)
{
mid = (l + r) >> 1;
if (a[mid].y == x)
{
return mid;
}
else if (a[mid].y < x)
{
res = mid;
l = mid + 1;
}
else
{
r = mid - 1;
}
}
return res;
}
int main()
{
//freopen("data.in", "r", stdin);
//freopen("result.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &a[i].y, &a[i].v);//y是年份,v是降雨量
}
build(1, 1, n);
int m; scanf("%d", &m);
while (m--)
{
int l, r; scanf("%d%d", &l, &r);
if (r <= l)
{
cout << "false\n";
continue;
}
if (l >= a[n].y || r <= a[1].y)
{
cout << "maybe\n";
continue;
}
int L = search_upper(l);
int R = search_lower(r);
if (a[L].y == l && a[R].y == r)
{
if (a[L].v >= a[R].v)
{
if (R - L == 1)
{
if (a[R].y - a[L].y == 1)
cout << "true\n";
else cout << "maybe\n";
continue;
}
ans res = query(1, 1, n, L + 1, R - 1);
if (res.v >= a[R].v)
{
cout << "false\n";
}
else
{
if (res.flg && a[L + 1].y == l + 1 && a[R - 1].y == r - 1)
{
cout << "true\n";
}
else
{
cout << "maybe\n";
}
}
}
else
{
cout << "false\n";
}
}
else if (a[R].y == r)
{
if (r - l == 1)
{
cout << "maybe\n";
continue;
}
if (R == L)
{
cout << "maybe\n";
continue;
}
int RR = search_lower(r - 1);
if (RR < L)
{
cout << "maybe\n";
continue;
}
ans res = query(1, 1, n, L, RR);
if (res.v >= a[R].v)
{
cout << "false\n";
}
else
{
cout << "maybe\n";
}
}
else if (a[L].y == l)
{
if (r - l == 1)
{
cout << "maybe\n";
continue;
}
int LL = search_upper(l + 1);
int RR = search_lower(r - 1);
if (RR < LL)
{
cout << "maybe\n";
continue;
}
ans res = query(1, 1, n, LL, RR);
if (res.v >= a[L].v)
{
cout << "false\n";
}
else
{
cout << "maybe\n";
}
}
else
{
cout << "maybe\n";
}
continue;
}
}
//-19 -8
有用点个赞呗@_@