【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行每行两个整数yi和ri,为年份和降雨量,按照年份从小到大排列,即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;}//如果本次查询的右端点确定,且最大值是在右端点处取得,则合法
}
}