[SCOI2007]降雨量

题面

题目描述

我们常常会说这样的话:“ \(X\) 年是自 \(Y\) 年以来降雨量最多的”。它的含义是 \(X\) 年的降雨量不超过 \(Y\) 年,且对于任意 \(Y<Z<X\)\(Z\) 年的降雨量严格小于 \(X\) 年。例如 \(2002,2003,2004\)\(2005\) 年的降雨量分别为 \(4920,5901,2832\)\(3890\),则可以说“ \(2005\) 年是自 \(2003\) 年以来最多的”,但不能说“ $2005 $年是自 \(2002\) 年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。

输入格式

输入仅一行包含一个正整数 \(n\),为已知的数据。

以下 \(n\) 行每行两个整数 \(t_i\)\(c_i\),为年份和降雨量,按照年份从小到大排列,即 \(t_i<t_{i+1}\)

下一行包含一个正整数 \(m\),为询问的次数。

以下 \(m\) 行每行包含两个数 \(P\)\(Q\) ,即询问“ \(Q\) 年是自 \(P\) 年以来降雨量最多的。”这句话是必真、必假还是“有可能”。

输出格式

对于每一个询问,输出truefalse或者maybe

输入输出样例

输入
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\leqslant n\leqslant50000\), \(1\le m\le10000\), \(-10^9\leqslant y_i\leqslant10^9\), \(1\leqslant r_i\leqslant10^9\)

说句闲话

没错,你没看错,为了契合我神奇的变量名,我改题面了

神帖再现

Solution

我们将题意简化。

假设有这么一串年份: t[1] t[2] t[3] t[4] t[5]

我们要判断的是“t[5]年是否为自t[1]以来降雨量最多的”。

ans=max(r[2],r[3],r[4]),分类讨论。

  • 如果r[5]已知,且ans>=r[5]时,不满足题目中的 “\(Z\) 年的降雨量严格小于 \(X\) 年”,输出false
  • 如果r[1]已知,且ans>=r[1]时:
    • 如果ans<r[5],因为 r[5]>ans>=r[1],不满足题目中的“\(X\) 年的降雨量不超过 \(Y\) 年”,输出false
    • 如果ans>=r[5],不满足题目中的 “\(Z\) 年的降雨量严格小于 \(X\) 年”,输出false
  • 如果r[5]r[1]已知,且r[5]>r[1]时,不满足题目中“ \(X\) 年的降雨量不超过 \(Y\) 年”,输出false
  • 以上即为所有输出false时可能的情况。当上述所有条件都不满足时:
    • t[1]~t[5]中任意一个年份的降雨量未知时,输出 maybe
    • 否则输出true

代入到题目中来。

\(ans\) 可以用线段树或ST表求得,这里我们以线段树为例子。(其实是因为线段树码量大看起来逼格更高)

首先,询问的起点年份(stt)和终点年份(end)是否已知是一切的关键。

我们怎么知道 \(p\)\(q\) 有没有在已知降雨量的年份中出现过?

输入格式中给出了一个重要条件:

按照年份从小到大排列,即 \(t_i<t_{i+1}\)

知道年份有序有什么用?

有序 \(\to\) 单调性 \(\to\) 二分 \(\to\) lower_bound!

int getid(int yr){
	return lower_bound(t+1,t+n+1,yr)-t;
}

查找第一个大于等于某一年份的已知年份的下标,还是分类讨论,设 x=getid(p),y=getid(q)

  • 当查找到的年份等于需要查找的年份(t[x]==p,t[y]==q

    当前年份的降雨量已知。

    因为需要 Query 的是 \((p,q)\),我们将线段树查询的起点 \(beg\) 设为 \(x+1\) ,因为 t[x+1]>t[x]

  • 当查找到的年份大于需要查找的年份(t[x]>p,t[y]>q

    当前年份的降雨量未知。

    因为 t[x],t[y] 一定是已知的第一个 \(>p,>q\) 的年份,我们将起点 \(beg\) 设为 \(x\)

read(n);
for(int i=1;i<=n;++i){
	read(t[i]);
    read(c[i]);
}
build(1,1,n);
----------------------------------
bool bg=1;
bool ed=1;
//标记查询起点和终点是否已知,已知为ture
read(p);
read(q);
int x=getid(p);
int y=getid(q);
int beg=x;
//线段树的查询起点
int stt=t[x],end=t[y];
//查询起点和终点的对应年份
int bgr=c[x],edr=c[y];
//查询起点和终点的对应降雨量
if(p!=stt)bg=0;
else beg++;
if(q!=end)ed=0;
int ans=Query(1,beg,y-1);
//(p,q)中降雨量的最大值

然后按照刚才的一系列操作,分别判断 falsemaybetrue

关于 maybe的判断,莫非要 \(p\sim q\) 循环一次判断是否全部已知?

你逗我!明明有 \(O(1)\) 的好不好!

我们已知:

p,q,p-q:起点点份,终点年份,两个年份间一共存了多少个年份

x,y,x-y:起点年份下标,终点年份下标,两个年份间一共存了多少个已知年份

p-q==x-yq-p,y-x也行,只要能对应的上),也就是中间的全部年份数量==中间已知的全部年份数量。。。

那不就行了嘛。


Code

#include<cmath>
#include<cstdio>
#include<algorithm>
#define int long long
using std::lower_bound;
const int maxn=50005;
const int inf=1e18;
bool mb;
int n,m,p,q;
int t[maxn],c[maxn];
struct Segment_tree{
	int mx;
	int l,r;
}a[maxn<<2];
int max(int x,int y){return x>y?x:y;}
void read(int&x){
	x=0;
	bool f=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+(ch^48);
		ch=getchar();
	}
	if(f)x=-x;
	return;
}
inline int getid(int yr){
	return lower_bound(t+1,t+n+1,yr)-t;
}
int obzmax(int x,int y){return x>y?x:y;}
void build(int p,int l,int r){
	a[p].l=l,a[p].r=r;
	if(l==r){
		a[p].mx=c[l];
		return;
	}
	int mid=l+r>>1;
	int lt=p*2;int rt=lt|1;
	build(lt,l,mid);
	build(rt,mid+1,r);
	a[p].mx=obzmax(a[lt].mx,a[rt].mx);
	return;
}
int Query(int p,int l,int r){
	if(a[p].l>=l&&a[p].r<=r)
		return a[p].mx;
	int val=-inf;
	int mid=a[p].l+a[p].r>>1;
	int lt=p*2;int rt=lt|1;
	if(l<=mid)
		val=obzmax(val,Query(lt,l,r));
	if(r>mid)
		val=obzmax(val,Query(rt,l,r));
	return val;
} 
signed main(){
	read(n);
	for(int i=1;i<=n;++i){
		read(t[i]);
		read(c[i]);
	}
	build(1,1,n);
	read(m);
	while(m--){
		bool bg=1;
		bool ed=1;
		read(p);
		read(q);
		int x=getid(p);
		int y=getid(q);
		int beg=x;
		int stt=t[x],end=t[y];
		int bgr=c[x],edr=c[y];
		if(p!=stt)bg=0;
		else beg++;
		if(q!=end)ed=0;
		int ans=Query(1,beg,y-1);
		if(bg&&ans>=bgr)
			puts("false");
		else if(ed&&ans>=edr)
			puts("false");
		else if(bg&&ed&&bgr<=edr)
			puts("false");
		else if(!bg||!ed||p-q!=x-y)
			puts("maybe");
		else puts("true");
	}
	return 0;
}

end.

posted @ 2021-01-05 23:44  XSC062  阅读(94)  评论(0编辑  收藏  举报