题解[SCOI2007]降雨量
Posted Refined_heart
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解[SCOI2007]降雨量相关的知识,希望对你有一定的参考价值。
\\(\\text{Solution:}\\)
Loj真好用)
观察一下发现我们只需要简单维护区间最大值就可以了。但是如何判断 maybe 的情况?
- 对于未知年份:
考虑我们如果不知道一对已知年份中有没有未知年份,那一定有一个未知年份是和一个已知年份相邻的。
所以,我们在离散化的时候将所有年份的左右相邻年份都加进去即可。(以防万一我加了相邻年份和相邻年份的相邻年份)
这样我们就解决了未知年份的问题。
- 对于判断是不是存在未知年份:
考虑我们要将那些我们加进去的虚拟年份赋什么样的值。首先它一定不能影响到我们维护的正常最大值,所以我们可以考虑给它赋值一个无穷小,同时维护一下区间最小值。这样,每次查询一个 pair 维护两个值:最大值最小值,就可以判断了。
- 对于三种情况的分类讨论:
下面根据题目描述称年份 \\(y,x\\) .
- 两个年份的降雨量都知道:
先判断 y 的降雨量是不是大于等于 x 的降雨量,不满足输出 false 。
然后查询区间\\([y+1,x-1].\\) 如果存在最大值大于 x 的降雨量输出 false ,否则如果存在最小值是 -inf 输出 maybe ,其他情况是 true 。
- 知道 x 的降雨量,不知道 y 的降雨量。
那就只有 false maybe 的判断了。只需要查询上述范围是不是有大于等于 x 降水量的年份即可。
- 两个年份的降雨量都不知道
显然 maybe 。
- 知道 y 的降雨量,不知道 x 的降雨量
这是一种比较隐蔽的情况,考虑会不会 false :
我们查询区间中的最大值,如果最大值要大于 y 的降雨量,这说明 x 必然不能作为 y 年份后最大降雨量的年份,而是应当作为这个最大值所在的年份。
否则输出 maybe 。
空间计算
由于离散化的时候我们建立的虚拟点比较多,所以空间需求自然要大。
用了动态开点的线段树,所以空间应该开到两倍;同时计算节点个数约为 \\(5*5*10^4+10*10^4=3.5*10^5.\\)
到了最后才发现 RE 的原因。以后空间问题一定要注意。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=2e6+10;
const int inf=21474836470ll;
int tot,n,m;
int ls[MAXN],rs[MAXN],rt=1,val[MAXN];
struct Tr{int l,r,maxn,minn;}tr[MAXN];
struct Q{int y,x;}q[MAXN];
struct N{int t,w;}a[MAXN];
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
inline void pushup(int x){
tr[x].maxn=Max(tr[ls[x]].maxn,tr[rs[x]].maxn);
tr[x].minn=Min(tr[ls[x]].minn,tr[rs[x]].minn);
}
void build(int &x,int l,int r){
x=++tot;
tr[x].l=l;
tr[x].r=r;
if(l==r){
tr[x].maxn=val[l];
tr[x].minn=val[l];
return;
}
int mid=(l+r)>>1;
build(ls[x],l,mid);
build(rs[x],mid+1,r);
pushup(x);
}
pair<int,int>query(int x,int l,int r){
pair<int,int>Ans;
Ans.first=-inf;
Ans.second=inf;
if(tr[x].l>=l&&tr[x].r<=r){
return make_pair(tr[x].maxn,tr[x].minn);
}
int mid=(tr[x].l+tr[x].r)>>1;
if(l<=mid){
pair<int,int>Ask=query(ls[x],l,r);
if(Ans.first==-inf&&Ans.second==inf){
Ans=Ask;
}
else{
Ans.first=Max(Ans.first,Ask.first);
Ans.second=Min(Ans.second,Ask.second);
}
}
if(mid<r){
pair<int,int>Ask=query(rs[x],l,r);
if(Ans.first==-inf&&Ans.second==inf){
Ans=Ask;
}
else{
Ans.first=Max(Ans.first,Ask.first);
Ans.second=Min(Ans.second,Ask.second);
}
}
return Ans;
}
int b[MAXN],bcnt,blen;
inline int getpos(int v){return lower_bound(b+1,b+blen+1,v)-b;}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;++i)scanf("%lld%lld",&a[i].t,&a[i].w),a[i].t+=1000000003;
for(int i=1;i<=n;++i){b[++bcnt]=a[i].t;b[++bcnt]=a[i].t+1;b[++bcnt]=a[i].t-1;b[++bcnt]=a[i].t+2;b[++bcnt]=a[i].t-2;}
scanf("%lld",&m);
for(int i=1;i<=m;++i){
int y,x;
scanf("%lld%lld",&y,&x);
y+=1000000003;
x+=1000000003;
b[++bcnt]=y;
b[++bcnt]=x;
b[++bcnt]=y+1;
b[++bcnt]=y-1;
b[++bcnt]=x+1;
b[++bcnt]=x-1;
b[++bcnt]=x-2;
b[++bcnt]=x+2;
b[++bcnt]=y-2;
b[++bcnt]=y+2;
q[i]=(Q){y,x};
}
sort(b+1,b+bcnt+1);
blen=unique(b+1,b+bcnt+1)-b-1;
int mx=-1;
for(int i=1;i<=n;++i)a[i].t=getpos(a[i].t);
for(int i=1;i<=n;++i)mx=Max(mx,a[i].t);
for(int i=1;i<=mx+10;++i)val[i]=-inf;
for(int i=1;i<=n;++i)val[a[i].t]=a[i].w;
build(rt,1,mx+10);
for(int i=1;i<=m;++i){
int pre=q[i].y;
int now=q[i].x;
pre=getpos(pre);
now=getpos(now);
if(val[now]!=-inf&&val[pre]!=-inf){
if(val[pre]<val[now]){
puts("false");
continue;
}
pair<int,int>qq=query(rt,getpos(q[i].y+1),getpos(q[i].x-1));
if(qq.first>=val[now]){
puts("false");
continue;
}
if(qq.second==-inf){
puts("maybe");
continue;
}
puts("true");
continue;
}
if(val[now]!=-inf&&val[pre]==-inf){
pair<int,int>qq=query(rt,pre,getpos(q[i].x-1));
if(qq.first>=val[now]){
puts("false");
continue;
}
puts("maybe");
continue;
}
if(val[now]==-inf&&val[pre]==-inf){
puts("maybe");
continue;
}
if(val[now]==-inf&&val[pre]!=-inf){
pair<int,int>qq=query(rt,getpos(q[i].y+1),getpos(q[i].x-1));
if(qq.first>=val[pre]){
puts("false");
continue;
}
puts("maybe");
continue;
}
}
return 0;
}
以上是关于题解[SCOI2007]降雨量的主要内容,如果未能解决你的问题,请参考以下文章