您的位置:首页 > 其它

BZOJ 1067[SCOI 2007]

2016-03-26 21:22 344 查看

1067: [SCOI2007]降雨量

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 3301  Solved: 850

[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


分析:

看到这么大的数据,就可以非常显然的想到是线段树,但是本题有非常多的限制和判断:

true的情况需要满足

  x与y的值都已知且y值<x值且x+1到y-1都已知并且都小于y值

maybe满足

 1.x值y值均未知

 2.已知x值未知y值并且x+1到y-1都已知并且都小于y值

 3.已知y值未知x值并且x+1到y-1都已知并且都小于x值

 4.x为年份最大一年,y>x

 5.y为年份最小一年,x<y

 6.x,y均已知且y<x并且x+1到y-1有未知并且都小于x值

其它都是false(源自:http://hzwer.com/1655.html

下面是代码;

#include<cstdio>
#include<iostream>
using namespace std;

struct d
4000
ata{int ly,ry,mx,know;}tr[200001];//ly,ry是线段树维护的范围
//mx表示从ly到ry年中降雨量的最大值,know表示从ly到ry年的降雨量是否都知道
int n,m;

void build(int k,int l,int r)//建树
{
if(l==r)
{
scanf("%d%d",&tr[k].ly,&tr[k].mx);
tr[k].ry=tr[k].ly;
tr[k].know=1;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tr[k].know=(tr[k<<1].know && tr[k<<1|1].know);
if(tr[k<<1].ry+1!=tr[k<<1|1].ly)tr[k].know=0;
tr[k].ly=tr[k<<1].ly;
tr[k].ry=tr[k<<1|1].ry;
tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}

int get(int k,int x)//找到x年的降雨量
{
if(tr[k].ly==tr[k].ry)
{
if(tr[k].ly!=x)return 0;
else return tr[k].mx;
}
if(tr[k<<1].ry>=x)return get(k<<1,x);
else
if(tr[k<<1|1].ly<=x)return get(k<<1|1,x);
return 0;
}

int getnext(int k,int x)
{
int l=tr[k].ly,r=tr[k].ry;
if(l==r)return tr[k].ly;
if(x<tr[k<<1].ry)return getnext(k<<1,x);
else
return getnext(k<<1|1,x);
}

int getlast(int k,int x)
{
int l=tr[k].ly,r=tr[k].ry;
if(l==r)return tr[k].ly;
if(x>tr[k<<1|1].ly)return getlast(k<<1|1,x);
else return getlast(k<<1,x);
}

int ask(int k,int x,int y,int num)//判断是否有哪一年的降雨量大于需要判断的年份
{
bool f=0;
if(x<tr[k].ly){f=1;x=tr[k].ly;}
if(tr[k].ly==x&&tr[k].ry==y)
{
if(tr[k].mx>=num)return 0;
else if(tr[k].know&&!f)return 1;
else return 2;
}
if(y<=tr[k<<1].ry)
return ask(k<<1,x,y,num);
else
if(x>=tr[k<<1|1].ly) return ask(k<<1|1,x,y,num);
else
{
int t1=ask(k<<1,x,tr[k<<1].ry,num);
int t2=ask(k<<1|1,tr[k<<1|1].ly,y,num);
if(!t1||!t2)return 0;
else
if(tr[k<<1].ry+1!=tr[k<<1|1].ly)return 2;
else
return 1;
}
}

int main()
{
int n;
scanf("%d",&n);
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
if(r<l){printf("false\n");continue;}
int lnum=get(1,l),rnum=get(1,r);
if(!lnum && !rnum)printf("maybe\n");
else
{
int s=getnext(1,l),t=getlast(1,r);
if(!lnum)
{
if(s>t||r==t){printf("maybe\n");continue;}
int f=ask(1,s,t,rnum);
if(f==0)printf("false\n");
else printf("maybe\n");
}
else
if(!rnum)
{
if(s>t||l==s){printf("maybe\n");continue;}
int f=ask(1,s,t,lnum);
if(f==0)printf("false\n");
else printf("maybe\n");
}
else
{
if(rnum>lnum){printf("false\n");continue;}
if(s>t)
{
if(l+1==r)printf("true\n");
else printf("maybe\n");
continue;
}
int f=ask(1,s,t,rnum);
if(f==0)printf("false\n");
else
if(f==1)
{
if(l+1==s&&r-1==t)printf("true\n");
else printf("maybe\n");
}
else if(ask(1,s,t,rnum)==2)printf("maybe\n");
else printf("false\n");
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  博客 bzoj 线段树