(POJ-2528)Mayor‘s posters(区间覆盖+离散化)

题目链接:https://vjudge.net/problem/POJ-2528

这道题问我们最后能看到多少张海报,如果正着想会比较麻烦,因为我们不确定当前的海报是否会被之后的海报所掩盖,但是我们可以肯定的是之后的海报一定不会被他之前的海报所掩盖,所以我们就可以倒着来贴海报,如果当前贴的海报能被看见,说明不会被之后的海报所遮挡,至于怎么查询是否被遮挡,这就是线段树的区间查询问题了。由于题目给的海报的边界比较大,数组无法直接存下,我们只需要存储他们的相对大小关系即可,所以我们需要用到离散化。

但是离散化时需要注意一些问题,比如三个区间:

1 10

1 4

6 10

答案显然是3,但是我们离散化后变成:

1 4

1 2

3 4

这样答案就变成2了,那这是为什么呢?

原本第2张海报和第三张海报之间是有间隔的,但是我们离散化后他们就变成相邻的了,于是如果有一张大海报包括他们的间隔,那么对答案就会造成影响,所以我们对于离散化之前不相邻的数之间加一个中间值,这样就可以消除这种影响,但是由于这道题目的数据比较水,即使不考虑这种情况也可以ac,但还是希望大家能够考虑到这种情况,毕竟下次遇到的题目数据就不一定那么水了。下面上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
vector<int>alls;
const int N=5e6+10;
int ll[N],rr[N],l[N],r[N],sum[N],lazy[N];
int find(int x)
{
	return (lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1);
}
void pushup(int id)
{
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
void pushdown(int id)
{
	if(lazy[id])
	{
		lazy[id<<1]=lazy[id];
		lazy[id<<1|1]=lazy[id];
		sum[id<<1]=(r[id<<1]-l[id<<1]+1)*lazy[id];
		sum[id<<1|1]=(r[id<<1|1]-l[id<<1|1]+1)*lazy[id];
		lazy[id]=0;
	}
}
void build(int id,int L,int R)
{
	l[id]=L;r[id]=R;sum[id]=0;lazy[id]=0;
	if(L==R) return ;
	int mid=L+R>>1;
	build(id<<1,L,mid);
	build(id<<1|1,mid+1,R);
	pushup(id);
}
void update_interval(int id,int L,int R,int val)
{
	if(l[id]>=L&&r[id]<=R)
	{
		sum[id]=(r[id]-l[id]+1)*val;
		lazy[id]=val;
		return ;
	}
	pushdown(id);
	int mid=l[id]+r[id]>>1;
	if(mid>=L) update_interval(id<<1,L,R,val);
	if(mid+1<=R) update_interval(id<<1|1,L,R,val);
	pushup(id); 
	return ;
}
int query_interval(int id,int L,int R)
{
	if(l[id]>=L&&r[id]<=R) return sum[id];
	pushdown(id);
	int mid=l[id]+r[id]>>1;
	int ans=0;
	if(mid>=L) ans+=query_interval(id<<1,L,R);
	if(mid+1<=R) ans+=query_interval(id<<1|1,L,R);
	return ans;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		alls.clear();
		scanf("%d",&n);
		build(1,1,4*n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d",&ll[i],&rr[i]);
			alls.push_back(ll[i]);
			alls.push_back(rr[i]);
		}
		sort(alls.begin(),alls.end());
		alls.erase(unique(alls.begin(),alls.end()),alls.end());
		int len=alls.size();
		//在离散化数组中相邻两个间隔大于1的数之间加一个中间值来消除间隔的影响 
		for(int i=1;i<len;i++)
			if(alls[i]-alls[i-1]>1)
				alls.push_back(alls[i-1]+1);
		sort(alls.begin(),alls.end());//排序 
		alls.erase(unique(alls.begin(),alls.end()),alls.end());//去重 
		int ans=0;
		for(int i=n;i>=1;i--)
		{
			int l1=find(ll[i]),r1=find(rr[i]);
			if(query_interval(1,l1,r1)!=r1-l1+1)
			{
				ans++;
				update_interval(1,l1,r1,1);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

上一篇:离散化


下一篇:【离散化】acwing802. 区间和