1067: [SCOI2007]降雨量
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1096 Solved: 241
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
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
true
false
maybe
false
HINT
100%的数据满足:1<=n<=50000, 1<=m<=10000, -10^9<=yi<=10^9, 1<=ri<=10^9
Source
bzoj评测链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1067
poj评测链接:http://poj.org/problem?id=2637
解法:
rmq问题,用st算法或线段树都ok,主要难的是对于各种条件的判断。我在这里讲的是st算法求解。用ma[i][j]代表区间[i][i+d[j]-1]内的最大值,flag[i][j]记录区间[i][i+d[j]-1]内是否存在降雨量未知的年份,用y[i]数组记录排在第i位的年份编号,用get(X)函数求得y【】数组从小到大,第一个大于等于x的位置。
1.为true的条件:
①Y<X;
②Y---->X年份的降雨量都已知;
③X年份的降雨量<=Y年份的降雨量;
④若get(X)-get(Y)==1,上述条件成立则为true
若get(X)-get(Y)>1,Max记为从Y+1年到X-1年的最大降雨量,若Max<X年份的降雨量,则为true;
2.为false的条件:
①若Y>=X,则为false;
②若已知X与Y年份的降雨量,X年份的降雨量大于Y年份的降雨量,则为false
③若已知X与Y年份的降雨量,且get(X)-get(y)>1,即X,Y年份中间还有其他年份,Max记为从get(Y)+1到get(X)-1年份的最大降雨量,若Max>=X年份的降雨量,则为false;
④若仅仅已知X年份的降雨量,且get(X)-get(y)>1,Max记为Y数组中从get(Y)到get(x)-1年份的最大降雨量,Max>=X年份的降 雨量,则为false;
⑤若仅仅已知Y年份的降雨量,且get(X)-get(Y)>1,Max记为Y数组中从get(Y)+1到get(X)-1年份的最大降雨量,Max>=Y年份的降 雨量,则为false;
如果你在bzoj上AC了这道题,在poj上却A不过,那么请检查你是否在每读入一组新数据时,都把flag数组memset过,如果没有,加上试一试。
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cctype>
#define maxn (50000+100)
#define inf 2000000000
#define false {printf("false\n");continue;}
#define true {printf("true\n");continue;}
#define maybe {printf("maybe\n");continue;}
using namespace std;
int n,m,y[maxn];
int d[17]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};
int ma[maxn][17];
bool flag[maxn][17];//1 代表区间存在不连续的部分
void init()
{
freopen("rain.in","r",stdin);
freopen("rain.out","w",stdout);
}
inline int getin()
{
int ans=0;bool sign=0;char tmp;
do tmp=getchar();
while(!isdigit(tmp) && tmp!='-');
if(tmp=='-')sign=1,tmp=getchar();
do ans=(ans<<3)+(ans<<1)+tmp-'0';
while(isdigit(tmp=getchar()));
return sign?-ans:ans;
}
void build()
{
int i,j; n=getin();
for(i=1;i<=n;i++)y[i]=getin(),ma[i][0]=getin();
for(i=1;i<n;i++)if(y[i]+1!=y[i+1])flag[i][1]=1;
y[n+1]=inf;
for(j=1;d[j]<=n;j++)
for(i=1;i+d[j]-1<=n;i++)
ma[i][j]=max(ma[i][j-1],ma[i+d[j-1]][j-1]);
for(j=2;d[j]<=n;j++)
for(i=1;i+d[j]-1<=n;i++)
if(flag[i][j-1] || flag[i+d[j-1]][j-1] || y[i+d[j-1]-1]+1!=y[i+d[j-1]])
flag[i][j]=1;
}
inline int get(int x)
{
int l=1,r=n,m;
while(l<=r)
{
m=(l+r)>>1;
if(x<=y[m])r=m-1;
else l=m+1;
}
return l;
}
void work()
{
build();
m=getin();
int i,a,b,k,Max,aa,bb;
for(i=1;i<=m;i++)
{
aa=getin(),bb=getin();
if(bb<=aa)false
a=get(aa),b=get(bb);
if(y[a]==aa && y[b]==bb)
{
if(ma[b][0]>ma[a][0])false
if(b-a==1)
{if(!flag[a][1])true}
else
{
k=int(log((b-a-1)*(1.0))/log(2.0));
Max=max(ma[a+1][k],ma[b-d[k]][k]);
if(Max>=ma[b][0])false
k=int(log((b-a+1)*(1.0))/log(2.0));
if(!flag[a][k] && !flag[b-d[k]+1][k] && !flag[a+d[k]-1][1])true
}
}
if(y[a]==aa && y[b]!=bb && b-a>=2)
{
k=int(log((b-a-1)*(1.0))/log(2.0));
Max=max(ma[a+1][k],ma[b-d[k]][k]);
if(Max>=ma[a][0])false;
}
if(y[a]!=aa && y[b]==bb && b-a>=1)
{
k=int(log((b-a)*(1.0))/log(2.0));
Max=max(ma[a][k],ma[b-d[k]][k]);
if(Max>=ma[b][0])false;
}
maybe;
}
}
int main()
{
init();
work();
return 0;
}