洛谷传送门
题目描述
我们常常会说这样的话:“X年是自Y年以来降雨量最多的”。它的含义是X年的降雨量不超过Y年,且对于任意Y
输入输出格式
输入格式:
输入仅一行包含一个正整数n,为已知的数据。以下n行每行两个整数yi和ri,为年份和降雨量,按照年份从小到大排列,即yi
输出格式:
对于每一个询问,输出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
输出样例#1:
false
true
false
maybe
false
说明
100%的数据满足:
1<=n<=50000,1<=m<=10000,−109<=yi<=109,1<=ri<=109
1
<=
n
<=
50000
,
1
<=
m
<=
10000
,
−
10
9
<=
y
i
<=
10
9
,
1
<=
r
i
<=
10
9
解题分析
博主在4个月前还是一枚萌新的时候打过这道题, 被各种特判坑到爆炸, 最后怎么调都有5个RE…
4个月后码力大增的博主又来尝试了这道题, 发现时间复杂度并不是问题, 于是为了避免线段树查询时出现左右区间爆炸的情况, 进行了暴力修改操作再改回去…
另外要注意一下坑点:
1.线段树查询的时候可能左边界大于右边界!因为左右边界可能长度只有1或2, 将左边界右边界++–后可能就爆炸了…(因此博主选择将左边界右边界修改为0)
2.lower_bound得到的位置所对应的值可能大于或小于查询值! 特别注意小于的情况, 因为可能查询的左区间比已知的最大年份都大…
3.注意题目中严格大于和大于等于的关系… 因此在判定是false 或 maybe 的时候是要判定区间中部的值是否大于等于左边界或右边界的值…
剩下的就只有码代码啦(10分钟)!调试两小时
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define MX 100005
#define lb tree[now].lef
#define rb tree[now].rig
static bool fu;
template <class T>
IN void in(T &x)
{
fu = false;
x = 0; R char c = gc;
W (!isdigit(c))
{if(c == '-' ) fu = true; c = gc;}
W (isdigit(c))
{x = (x << 1) + (x << 3) + c - 48, c = gc;}
if(fu) x = -x;
}
namespace SGT
{
using std::max;
struct Node
{
int val, son[2], mx, lef, rig;
}tree[MX << 2];
struct Data
{
int year, val;
}dat[MX];
IN bool operator < (const Data &x, const Data &y)
{return x.year < y.year;}
int dot, q;
IN void pushup(const int &now)
{tree[now].mx = max(tree[ls].mx, tree[rs].mx);}
void build(const int &now, const int &lef, const int &rig)
{
lb = lef, rb = rig;
if(lb == rb)
{
tree[now].val = tree[now].mx = dat[lb].val;
return;
}
int mid = (lef + rig) >> 1;
ls = now << 1; rs = now << 1 | 1;
build(ls, lb, mid);
build(rs, mid + 1, rb);
pushup(now);
}
int query(const int &now, const int &lef, const int &rig)
{
if(lb >= lef && rb <= rig) return tree[now].mx;
int mid = (lb + rb) >> 1;
int rt = -1;
if(mid >= lef) rt = max(rt, query(ls, lef, rig));
if(mid < rig) rt = max(rt, query(rs, lef, rig));
return rt;
}
void modify(const int &now, const int &tar, const int &del)
{
if(lb == tar && rb == tar)
{
tree[now].val = del;
tree[now].mx = del;
return;
}
int mid = (lb + rb) >> 1;
if(tar <= mid) modify(ls, tar, del);
else modify(rs, tar, del);
pushup(now);
}
IN short work(const int &a, const int &b)
{
if(a > b) return 2;
if(a == b) return 1;
bool emp = false, big = false;//emp 指中间有未知年份的情况
int lef = std::lower_bound(dat + 1, dat + 1 + dot, (Data){a, 0}) - dat;
if(dat[lef].year != a) emp = true;//注意不能只判小于
if(dat[lef].year < a) lef++;
int rig = std::lower_bound(dat + 1, dat + 1 + dot, (Data){b, 0}) - dat;
if(dat[rig].year != b) emp = true;//同上
if(dat[rig].year > b) rig--;
if(rig <= lef) return 3;//非法
if(dat[rig].year != b && dat[lef].year != a) return 3;//两边都不知道, 直接返回maybe
if(rig - lef != b - a) emp = true;//中间有空位(数量不对应)
if(dat[rig].year == b && dat[lef].year == a)
{
int va1 = query(1, lef, lef);
int va2 = query(1, rig, rig);
if(va1 < va2) return 2;
modify(1, lef, 0);
modify(1, rig, 0);
if(query(1, lef, rig) >= va2)
{modify(1, lef, va1), modify(1, rig, va2); return 2;}
modify(1, lef, va1);
modify(1, rig, va2);
if(emp) return 3;
return 1;
}
else if(dat[rig].year == b)
{
int va1 = query(1, rig, rig);
modify(1, rig, 0);
if(query(1, lef, rig) >= va1) {modify(1, rig, va1); return 2;}
modify(1, rig, va1);
return 3;
}
else
{
int va1 = query(1, lef, lef);
modify(1, lef, 0);
if(query(1, lef, rig) >= va1) {modify(1, lef, va1); return 2;}
modify(1, lef, va1);
return 3;
}
}
}
using namespace SGT;
int main(void)
{
int a, b;
in(dot);
for(R int i = 1; i <= dot; ++i) in(dat[i].year), in(dat[i].val);
build(1, 1, dot);
in(q);
W (q--)
{
in(a), in(b);
switch(work(a, b))
{
case 1: printf("true\n"); break;
case 2: printf("false\n"); break;
case 3: printf("maybe\n"); break;
}
}
}