[SCOI2007]降雨量
跨越大半年的更新
题目链接(点我)
题面描述
我们常常会说这样的话:“X 年是自 Y 年以来降雨量最多的”。它的含义是 X 年的降雨量不超过 Y 年,且对于任意 Y<Z<X,Z 年的降雨量严格小于 X 年。例如 2002,2003,2004 和 2005 年的降雨量分别为 4920,5901,2832 和 3890,则可以说“2005 年是自 2003 年以来最多的”,但不能说“2005 年是自 2002 年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。
输入格式
输入仅一行包含一个正整数n,为已知的数据。以下n行每行两个整数yi和ri,为年份和降雨量,按照年份从小
到大排列,即yi<yi+1。下一行包含一个正整数m,为询问的次数。以下m行每行包含两个数Y和X,即询问“X年是
自Y年以来降雨量最多的。”这句话是必真、必假还是“有可能”。
输出格式
对于每一个询问,输出true
,false
或者maybe
。
做法:
假设年降水量为w[i]
x,y为所求年份,l,r为其所对应的坐标,z=max(w[l+1~r-1])
由于输入的时候保证年份递增,因此没有必要离散化吧。。。
接下来就是分类讨论
if(x&&z>=x) false;
if(y&&z>=y) false;
if(x&&y),x<y false;
else
if(x&&y&&l-r+1==y-x-1) true;
else maybe;
最大值采用线段树维护,l,r采用二分查找,详见代码:
代码:
#include<bits/stdc++.h> #define mid (l+r)/2 using namespace std; const int N=5e4+10; int a[N],w[N],n; int t[N<<2]; void build(int i,int l,int r){ if(l==r){ t[i]=w[l]; return ; } build(2*i,l,mid); build(2*i+1,mid+1,r); t[i]=max(t[2*i],t[2*i+1]); } int query(int i,int l,int r,int L,int R){ if(L>R) return -1e9; if(l>=L&&r<=R) return t[i]; int ret=0; if(L<=mid) ret=max(ret,query(2*i,l,mid,L,R)); if(R>mid) ret=max(ret,query(2*i+1,mid+1,r,L,R)); return ret; } int main(){ int q; scanf("%d",&n); a[0]=1e9+7,a[n+1]=-(1e9+7); for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&w[i]); build(1,1,n); scanf("%d",&q); while(q--){ int x,y; scanf("%d%d",&x,&y); int l=lower_bound(a+1,a+n+1,x)-a;while(a[l]<=x) l++; int r=lower_bound(a+1,a+n+1,y)-a;while(a[r]>=y) r--; int z=query(1,1,n,l,r); if((a[r+1]==y&&z>=w[r+1])||(a[l-1]==x&&z>=w[l-1])||(a[l-1]==x&&a[r+1]==y&&w[l-1]<w[r+1])) puts("false"); else{ if(r-l+1==y-x-1&&a[l-1]==x&&a[r+1]==y) puts("true"); else puts("maybe"); } } return 0; }
自己选择的路,跪着也要走完