P3740 [HAOI2014]贴海报

区间覆盖怎么能不用线段树数呢(线段树又短又好写).
可以发现每次覆盖的是一个区间,但是这个区间很大所以需要离散化.
如果直接离散化会出现一些很奇怪的情况:在这里插入图片描述
如这样一个图,在普通的离散化后会变成:
在这里插入图片描述
红色的海报本来是可以看见的但是在离散化就看不见了,所以,在离散化时,如果两个相邻的值的差不是1(即中间有缝隙),需要在中间空一个位置出来.
下面放上完整的代码:

#include<bits/stdc++.h>
#define rap(i,first,last) for(int i=first;i<=last;++i)
#define Lson now*2
#define Rson now*2+1
#define Middle (left+right)/2
#define Left Lson,left,Middle
#define Right Rson,Middle+1,right
#define Now nowleft,nowright
using namespace std;
const int maxN=1e6+7;
int N,M;
int tree[maxN*4];
int lazy[maxN*4];
void PushUp(int now)//合并
{
	tree[now]=tree[Lson]+tree[Rson];
}
void Down(int now,int left,int right,int _lazy)//推懒标记
{
	lazy[now]=_lazy;
	tree[now]=(right-left+1)*_lazy;	
}
void PushDown(int now,int left,int right)//向下推懒标记
{
	if(lazy[now])//如果有覆盖
	{
		Down(Left,lazy[now]);//向左子树推懒标记
		Down(Right,lazy[now]);//向右子树推懒标记
		lazy[now]=0;//懒标记清空
	}
}
void UpData(int nowleft,int nowright,int cover,int now=1,int left=1,int right=N)//区间覆盖
{
	if(left>nowright||nowleft>right)return;//不在范围内退出
	if(nowleft<=left&&right<=nowright)//可以直接修改
	{
		tree[now]=(right-left+1)*cover;
		lazy[now]=cover;
		return;
	}
	PushDown(now,left,right);//推懒标记
	UpData(Now,cover,Left);//修改左子树
	UpData(Now,cover,Right);//修改右子树
	PushUp(now);//合并
}
int Query(int who,int now=1,int left=1,int right=N)//单点查询
{
	if(who<left||who>right)return 0;//不在范围内
	if(left==right)//已经是叶节点了可以直接返回
	{	
		return tree[now];
	}
	PushDown(now,left,right);//推懒标记
	int result=Query(who,Left);//从左右子树处获得答案
	result+=Query(who,Right);
	PushUp(now);//合并
	return result;//返回答案
}
map<int,int>Hash;//离散化
int arr[maxN*2];
int L[maxN],R[maxN];
int check[maxN];
int main()
{
	scanf("%d%d",&N,&M);
	rap(i,1,M)
	{
		scanf("%d%d",&L[i],&R[i]);
		arr[i*2-1]=L[i];
		arr[i*2]=R[i];
	}
	
	sort(arr+1,arr+M*2+1);//离散化部分
	arr[0]=-1;
	int N=0;
	rap(i,1,M*2)
	{
		if(arr[i]!=arr[i-1])
		{
			if(arr[i-1]+1!=arr[i])//上方讲的注意点
			N+=2;
			else
			N++;
			Hash[arr[i]]=N;
		}
	}
	
	rap(i,1,M)
	{
		UpData(Hash[L[i]],Hash[R[i]],i);//修改
	}
	int now,answer=0;
	check[0]=1;
	rap(i,1,N)//每个点查询,看有几种海报,用bool型数组记录
	{
		now=Query(i);//查询出这个位置的值
		if(!check[now])//如果没有过则answer+1
		{
			check[now]=1;
			answer++;
		}
	}
	printf("%d",answer);//输出answer
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值