POJ2528 Mayor's posters(线段树&区间更新+离散化)题解

题意:给一个区间,表示这个区间贴了一张海报,后贴的会覆盖前面的,问最后能看到几张海报。

思路:

之前就不会离散化,先讲一下离散化:这里离散化的原理是:先把每个端点值都放到一个数组中并除重+排序,我们就得到了处理后的数组,现在我们只需要用二分查找端点值在整个数组的下标,这样就达到了离散化的目的,压缩了长度。因为这里很特殊,不能用一般的离散化去做,如果区间两端只差1,那么需要给这个区间再加一个值,这个其他题解讲到了。

这里的区间更新和上一题不太一样,有一些地方要注意一下


代码:

#include<queue>
#include<cstring>
#include<set>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define ll long long
const int N=100005;
const int MOD=20071027;
using namespace std;
int lw[N],rw[N],x[N<<1],color[N<<2];
void push_down(int rt){
	if(color[rt]!=-1){
		color[rt<<1]=color[rt<<1|1]=color[rt];
		color[rt]=-1;
	}
}
void update(int rt,int l,int r,int L,int R,int co){ //l r为访问区间 
	if(L<=l && R>=r){
		color[rt]=co;
		return;
	}
	push_down(rt);	//注意传值 
	int m=(l+r)/2;
	if(L<=m){	//这里只能在L取等 
		update(rt<<1,l,m,L,R,co);
	}
	if(R>m){	//这里不能取等,取等时代入m+1就错了 
		update(rt<<1|1,m+1,r,L,R,co);
	}
}
set<int> col;
void query(int l,int r,int rt){
	if(color[rt]!=-1){
		col.insert(color[rt]);
		return;
	}
	if(l==r) return;
	int m=(l+r)/2;
	query(l,m,rt<<1);
	query(m+1,r,rt<<1|1);
}
int main(){
	int n,num,T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		num=0;
		for(int i=0;i<n;i++){
			scanf("%d%d",&lw[i],&rw[i]);
			x[num++]=lw[i];
			x[num++]=rw[i];
		}
		sort(x,x+num);
		int cnt=unique(x,x+num)-x;	//去掉重复的点 
		for(int i=cnt-1;i>0;i--){	//相邻两数相差大于1,中间再添一个数 
			if(x[i]!=x[i-1]+1)  x[cnt++]=x[i-1]+1;
		}
		sort(x,x+cnt);
		memset(color,-1,sizeof(color));
		for(int i=0;i<n;i++){	//离散化 
			int L=lower_bound(x,x+cnt,lw[i])-x;
			int R=lower_bound(x,x+cnt,rw[i])-x;
			update(1,0,cnt,L,R,i);
		}
		col.clear();
		query(0,cnt,1);
		printf("%d\n",col.size());
	}
    return 0;  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值