1067: [SCOI2007]降雨量
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3349 Solved: 862
[ Submit][ Status][ Discuss]
Description
我们常常会说这样的话:“X年是自Y年以来降雨量最多的”。它的含义是X年的降雨量不超过Y年,且对于任意Y<Z<X,Z年的降雨量严格小于X年。例如2002,2003,2004和2005年的降雨量分别为4920,5901,2832和3890,则可以说“2005年是自2003年以来最多的”,但不能说“2005年是自2002年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。
Input
输入仅一行包含一个正整数n,为已知的数据。以下n行每行两个整数yi和ri,为年份和降雨量,按照年份从小到大排列,即yi<yi+1。下一行包含一个正整数m,为询问的次数。以下m行每行包含两个数Y和X,即询问“X年是自Y年以来降雨量最多的。”这句话是必真、必假还是“有可能”。
Output
对于每一个询问,输出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
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
true
false
maybe
false
HINT
100%的数据满足:1<=n<=50000, 1<=m<=10000, -10^9<=yi<=10^9, 1<=ri<=10^9
Source
题解:线段树维护区间最值。如果读入的两个数不是连续的,那么就在他们中间加入一个中间年份,把降雨量值付为0, 然后如果区间最小值为0,就说明两个年份之间有未知年份,这样就进行各种分类讨论,乱搞一下就好了。分类讨论特别容易漏情况,特别容易出错。。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100003
using namespace std;
int n,m;
int y[N],num[N],a[N],c[N],tot,tr[N*4],tr1[N*4];
void update(int x)
{
tr[x]=max(tr[x<<1],tr[x<<1|1]);
tr1[x]=min(tr1[x<<1],tr1[x<<1|1]);
}
void build(int now,int l,int r)
{
if(l==r)
{
tr[now]=tr1[now]=c[l];
return;
}
int mid=(l+r)/2;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
int qjmax(int now,int l,int r,int ll,int rr)
{
if (l>=ll&&r<=rr) return tr[now];
int mid=(l+r)/2;
int ans=0;
if (ll<=mid)
ans=max(ans,qjmax(now<<1,l,mid,ll,rr));
if (rr>mid)
ans=max(ans,qjmax(now<<1|1,mid+1,r,ll,rr));
return ans;
}
int qjmin(int now,int l,int r,int ll,int rr)
{
if (l>=ll&&r<=rr) return tr1[now];
int mid=(l+r)/2;
int ans=1e9;
if (ll<=mid)
ans=min(ans,qjmin(now<<1,l,mid,ll,rr));
if (rr>mid)
ans=min(ans,qjmin(now<<1|1,mid+1,r,ll,rr));
return ans;
}
int main()
{
scanf("%d",&n);
int x,y1;
scanf("%d%d",&x,&y1);
tot++; a[tot]=tot; c[tot]=0; y[tot]=x-1;
tot++; a[tot]=tot; c[tot]=y1; y[tot]=x; num[1]=x;
for (int i=2;i<=n;i++)
{
int x,y1; scanf("%d%d",&num[i],&y1);
if (num[i]!=num[i-1]+1)
{
tot++;
a[tot]=tot; c[tot]=0; y[tot]=num[i-1]+1;
}
tot++; a[tot]=tot; c[tot]=y1; y[tot]=num[i];
}
build(1,1,tot);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int x,y1; scanf("%d%d",&x,&y1);
int k=lower_bound(y+1,y+tot+1,x)-y;
if (y[k]>x) k--;
int l=lower_bound(y+1,y+tot+1,y1)-y;
if (k==l-1)
if (y[k]==x&&y[l]==y1&&c[k]&&c[l])
{
if (c[k]>=c[l])
{
printf("true\n");
continue;
}
printf("false\n");
continue;
}
else
{
printf("maybe\n");
continue;
}
int minn=qjmin(1,1,tot,k+1,l-1);
int maxn=qjmax(1,1,tot,k+1,l-1);
if ((y[k]!=x||c[k]==0)&&(y[l]!=y1||c[l]==0))
{
printf("maybe\n");
continue;
}
if ((y[k]!=x||c[k]==0)&&y[l]==y1)
{
if (maxn>=c[l]) printf("false\n");
else printf("maybe\n");
continue;
}
if ((y[l]!=y1||c[l]==0)&&y[k]==x)
{
if (c[k]<=maxn) printf("false\n");
else printf("maybe\n");
continue;
}
if (maxn>=c[l]||c[k]<=maxn||c[l]>c[k]){
printf("false\n");
continue;
}
if(!minn) { printf("maybe\n");
continue;
}
printf("true\n");
}
}
数据生成器
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<map>
using namespace std;
int a[1000];
map<int,int> mp;
int main()
{
freopen("ok.in","w",stdout);
int n=200; int m=200; int p=2*n;
cout<<n<<endl; int x;
srand(time(0));
for (int i=1;i<=n;i++)
{
x=rand()%p+1;
while (mp[x]) x=rand()%p+1;
mp[x]=1;
a[i]=x;
}
sort(a+1,a+n+1);
for (int i=1;i<=n;i++)
{
cout<<a[i]<<" "<<rand()<<endl;
}
cout<<m<<endl;
for (int i=1;i<=m;i++)
{
int x,y; x=rand()%p+1; y=rand()%p+2;
if (x==y) y++;
if (x>y) swap(x,y);
cout<<x<<" "<<y<<endl;
}
}