bzoj 1067: [SCOI2007]降雨量

1067: [SCOI2007]降雨量

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 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

Sample Output

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;
   }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值