【codevs 2439】降雨量2007年省队选拔赛四川(线段树)

2439 降雨量2007年省队选拔赛四川

 时间限制: 1 s 空间限制: 64000 KB  题目等级 : 大师 Master

题目描述 Description

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

输入描述 Input Description

    输入仅一行包含一个正整数n,为已知的数据。以下n行每行两个整数yiri,为年份和降雨量,按照年份从小到大排列,即yi<yi+1。下一行包含一个正整数m,为询问的次数。以下m行每行包含两个数Y和X,即询问“X年是自Y年以来降雨量最多的。”这句话是必真、必假还是“有可能”。

输出描述 Output Description

    对于每一个询问,输出true,false或者maybe。

样例输入 Sample Input

    6

    2002 4920

    2003 5901

    2004 2832

    2005 3890

    2007 5609

    2008 3024

    5

    2002 2005

    2003 2005

    2002 2007

    2003 2007

    2005 2008

样例输出 Sample Output

    false

    true

    false

    maybe

    false

数据范围及提示 Data Size & Hint

    100%的数据满足:1<=n<=50000, 1<=m<=10000,-109<=yi<=109, 1<=ri<=109

 【题解】【线段树】

#include<map>
#include<cmath> 
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; 
map<int,int>hash;
int sum[200010];
int yue[50010],rain[50010],n,m;
inline void updata(int now)
{
	sum[now]=max(sum[(now<<1)],sum[(now<<1)|1]);
}
inline void build(int now,int l,int r)
{
	if (l==r) {sum[now]=rain[l]; return;}
	int mid=(l+r)>>1;
	build((now<<1),l,mid);
	build((now<<1)|1,mid+1,r);
	updata(now);
}
inline int ask(int now,int al,int ar,int l,int r)
{
	if (al<=l&&r<=ar) return sum[now];
	int mid=(l+r)>>1,maxn=0;
	if (al<=mid) maxn=max(maxn,ask((now<<1),al,ar,l,mid));
	if (ar>mid) maxn=max(maxn,ask((now<<1)|1,al,ar,mid+1,r));
	return maxn; 
}
int main()
{
	int i,j;
	scanf("%d",&n);
	hash.clear();
	for (i=1;i<=n;++i)
	 {
	 	scanf("%d%d",&yue[i],&rain[i]);
	 	hash[yue[i]]=i;
	 }
	build(1,1,n);
	scanf("%d",&m);
	for (i=1;i<=m;++i)
	 {
	 	int x,y,xl,yl;
	 	bool t1=0,t2=0,re=0;
	 	scanf("%d%d",&y,&x);
	 	if (hash[y]) t1=1,yl=hash[y];
	 	  else yl=lower_bound(yue+1,yue+n+1,y)-yue;
	 	if (hash[x]) t2=1,xl=hash[x];
	 	  else xl=lower_bound(yue+1,yue+n+1,x)-yue-1;
	 	if (!t1&&!t2) 
		   {printf("maybe\n"); continue;}//如果左右端点都不在序列里,那么序列的合法性无法确定
		if (t1&&t2&&rain[hash[y]]<rain[hash[x]])
	 	   {printf("false\n"); continue;}//如果两年在原序列中都存在,但y年的降雨量小于x年,则不合法
		if (t1&&!t2)
		  for (j=yl+1;j<=xl;++j)
		   if (rain[yl]<=rain[j]) 
		      {printf("false\n"); re=1; break;}//如果左端点在序列里,右端点不在序列里,但处于区间中的年份的降雨量不是严格小于y年,则不合法
	    if (re) continue;
	    if (t1&&!t2&&!re) {printf("maybe\n"); continue;}//如果左端点在序列里,右端点不在序列里,处于区间中的年份的降雨量严格小于y年,则合法性不确定 
	    if (!t1&&t2)
		  for (j=yl;j<xl;++j)
		    if (rain[j]>=rain[xl]) 
			   {printf("false\n"); re=1;break;}//如果左端点不在序列里,右端点在序列里,而区间中的年份的降水量不是严格小于x年,则不合法
	    if (re) continue; 
	    if (t2&&t1)
	      for (j=yl+1;j<xl;++j)
	        if (rain[j]>=rain[xl]) 
			   {printf("false\n"); re=1;break;}//如果两端点都在序列里,但区间中的年份的降水量不是严格小于x年,则不合法
		if (re) continue;
		if (x>y&&xl==yl||x-y>1&&yl+1==xl)  
		   {printf("maybe\n"); continue;}//如果左右端点在同一区间,那么序列的合法性不确定
		for (j=yl+2;j<=xl;++j)
		   if (yue[j]-yue[j-1]>1)  {printf("maybe\n"); re=1;break;}//如果当前区间中的年份不连续,则序列的合法性不确定
		if (re) continue;
		if (t1&&t2&&xl-yl==1&&x-y>2) {printf("maybe\n"); continue;}//如果在原序列中两年份是挨着的,但实际上不相邻,则合法性不确定 
		int ans=ask(1,yl+1,xl,1,n); 
		if (!hash[y+1]&&t2&&ans==rain[xl]) {printf("maybe\n"); continue;}//如果原序列的左右端点都确定,且最大值在右端点处取得,但y+1年不确定,即这个左开右闭区间的第一个元素不确定,则合法性不确定 
		if (!t1&&t2&&ans==rain[xl]) 
		    {printf("maybe\n"); continue;}//如果本次查询的左端点不在序列里,右端点在序列里,且最大值是在右端点处取得,那么序列的合法性不确定 
		if (t2&&ans!=rain[xl]) 
		   {printf("false\n"); continue;}//如果本次查询的右端点确定,且最大值不是在右端点处取得,则不合法
		if (t1&&t2)
		 for (j=yl+2;j<=xl;++j)
		   if (yue[j]-yue[j-1]>1)  {printf("maybe\n"); re=1;break;}//如果区间确定,但当前区间中的年份不连续,则序列的合法性不确定
		if (re) continue;
		if (t2&&ans==rain[xl]) 
		   {printf("true\n"); continue;}//如果本次查询的右端点确定,且最大值是在右端点处取得,则合法 
	 }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值