[poj 2528] Mayor's Posters[线段树][区间更新]

题意:

在单位高,w长的板上贴单位高,wi长的海报.会overlap,求最终能露出来的海报.


离散化的地方需要注意一下.


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 11111;
bool hash[maxn];
int li[maxn] , ri[maxn];
int X[maxn*3];
int col[maxn<<4];//离散化的时候上限已经乘了2*2
int cnt;
/**
    这道题是用到了线段树的成段替换,查询功能.
    由于是涂色问题,lazy标记本身就是数据域.
    对坐标需要进行单位区间的离散化(相对于点离散化).
    用了二分查找.
**/
//用到的是成段替换
//这个不需要向上更新,因为col即表示这一段的颜色,都是同一个值,就是数据域
void PushDown(int rt) {
	if (col[rt] != -1) {//因为col是0..m-1
		col[rt<<1] = col[rt<<1|1] = col[rt];
		col[rt] = -1;//表示当前根节点的区间内不只有一个颜色.
		//PushDown的时候一定是在扩展,那么一定就不同
	}
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		col[rt] = c;//更新到此节点,不向下扩展
		return ;
	}
	PushDown(rt);//否则向下扩展到子节点
	int m = (l + r) >> 1;//再按需要更新子节点
	if (L <= m) update(L , R , c , lson);
	if (m < R) update(L , R , c , rson);
}
void query(int l,int r,int rt) {
	if (col[rt] != -1) {
		if (!hash[col[rt]]) cnt ++;
		hash[ col[rt] ] = true;
		return ;
	}
	if (l == r) return ;//可能有空白区域,没涂色.搜索截止,不计数.
	int m = (l + r) >> 1;
	query(lson);
	query(rson);
}
int Bin(int key,int n,int X[]) {//二分查找key对应的下标
	int l = 0 , r = n - 1;
	while (l <= r) {
		int m = (l + r) >> 1;
		if (X[m] == key) return m;
		if (X[m] < key) l = m + 1;
		else r = m - 1;
	}
	return -1;
}
int main() {
	int T , n;
	scanf("%d",&T);
	while (T --) {
		scanf("%d",&n);
		int nn = 0;
		for (int i = 0 ; i < n ; i ++) {
			scanf("%d%d",&li[i] , &ri[i]);
			X[nn++] = li[i];//将原始端点们顺序存储
			X[nn++] = ri[i];
		}
		sort(X , X + nn);//升序
		int m = 1;
		for (int i = 1 ; i < nn; i ++) {//由于i>=m,m覆盖的部分已经没用了
			if (X[i] != X[i-1]) X[m ++] = X[i];
		}//在原位置上直接替换,离散化:将用到的不同端点映射到1..n位置(此时数值不变)
		for (int i = m - 1 ; i > 0 ; i --) {
        //中间有空余点的话,添进去一个恰好大1的值(已确定不重复),添在末尾,待以后排序
			if (X[i] != X[i-1] + 1) X[m ++] = X[i-1] + 1;
		}//倒序循环,最后一个是m - 1
		sort(X , X + m);//m刚好++过
		memset(col , -1 , sizeof(col));//build
		for (int i = 0 ; i < n ; i ++) {
			int l = Bin(li[i] , m , X);
			int r = Bin(ri[i] , m , X);
			update(l , r , i , 0 , m - 1 , 1);
		}
		cnt = 0;
		memset(hash , false , sizeof(hash));
		query(0 , m - 1 , 1);
		printf("%d\n",cnt);
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值