【题解】[SCOI2007]降雨量

Problem

\(\text{Solution:}\)

Loj真好用)

观察一下发现我们只需要简单维护区间最大值就可以了。但是如何判断 maybe 的情况?

  • 对于未知年份:

考虑我们如果不知道一对已知年份中有没有未知年份,那一定有一个未知年份是和一个已知年份相邻的。

所以,我们在离散化的时候将所有年份的左右相邻年份都加进去即可。(以防万一我加了相邻年份和相邻年份的相邻年份)

这样我们就解决了未知年份的问题。

  • 对于判断是不是存在未知年份:

考虑我们要将那些我们加进去的虚拟年份赋什么样的值。首先它一定不能影响到我们维护的正常最大值,所以我们可以考虑给它赋值一个无穷小,同时维护一下区间最小值。这样,每次查询一个 pair 维护两个值:最大值最小值,就可以判断了。

  • 对于三种情况的分类讨论:

下面根据题目描述称年份 \(y,x\) .

  1. 两个年份的降雨量都知道:

先判断 y 的降雨量是不是大于等于 x 的降雨量,不满足输出 false 。

然后查询区间\([y+1,x-1].\) 如果存在最大值大于 x 的降雨量输出 false ,否则如果存在最小值是 -inf 输出 maybe ,其他情况是 true 。

  1. 知道 x 的降雨量,不知道 y 的降雨量。

那就只有 false maybe 的判断了。只需要查询上述范围是不是有大于等于 x 降水量的年份即可。

  1. 两个年份的降雨量都不知道

显然 maybe 。

  1. 知道 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;
}
posted @ 2021-06-24 16:52  Refined_heart  阅读(81)  评论(0编辑  收藏  举报