poj 2528 Mayor's posters

31 篇文章 0 订阅
19 篇文章 0 订阅

Problempoj.org/problem?id=2528

参考blog.csdn.net/non_cease/article/details/7383736

离散化要注意的一个细节上述参考博客讲得挺清楚的。

然而还有一个不太懂的问题(仿佛是个坑),就是有个数组不知道为什么要开那么大。

就是 tree[],是线段树的数组,N 个人,每人左、右边界两个值,最多的情况 2N 个值,然后线段树开 4 倍,

所以就 tree [ N * 2 * 4 ],即 tree [ N << 3 ],但会WA,改成 tree [ N << 4 ] 就可以;

其实还有一个是 pos[],离散化用的数组,因为最多的情况是 2N,所以开 pos [ N << 1 ],但会 RE,开 pos [ N << 2 ] 就可以,因为离散化的时候还要插多一些值进去(见参考博文),最多的情况应该是:原本没有重复(unique() 后没有减少)、离散化时每个数都要多插一个值,就变成 2N * 2,所以要开 pos [ N << 2 ]。

还有,update() 和 query() 的时候用左闭右开形式的区间错了好多次,后来换成闭区间的形式才过的。

Source Code

#include <cstdio>
#include <cstring>
#include <bitset>
#include <algorithm>
using namespace std;
const int N = 10004;

int tree[N<<4];	// 线段树数组,记成段的颜色
int l[N], r[N];	// 每个人的左、右边界
int pos[N<<2];	// 用于边界的离散化
bitset<N> bs;	// 记录最后能显示的那些标号

void pushdown(int x)
{
	if(~tree[x])
	{
		tree[x<<1] = tree[x<<1|1] = tree[x];
		tree[x] = -1;
	}
}

void update(int ul, int ur, int v, int l, int r, int id)
{
	if(ul <= l && r <= ur)
	{
		tree[id] = v;
		return;
	}
	pushdown(id);
	int m = l + r >> 1;
	if(ul <= m)
		update(ul, ur, v, l, m, id<<1);
	if(ur > m)
		update(ul, ur, v, m+1, r, id<<1|1);
}

void query(int l, int r, int id)
{
	if(~tree[id])
	{
		bs[tree[id]] = 1;
		return;
	}
	if(l == r) return;
	int m = l + r >> 1;
	query(l, m, id<<1);
	query(m+1, r, id<<1|1);
}

int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		int n, top = 0;
		scanf("%d", &n);
		for(int i=0; i<n; ++i)
		{
			scanf("%d%d", l+i, r+i);
			pos[top++] = l[i];
			pos[top++] = r[i];
		}
		sort(pos, pos + top);
		top = unique(pos, pos + top) - pos;
		// 离散化坑点的解决:插值
		for(int i=top-1; i>0; --i)
			if(pos[i] != pos[i-1] + 1)
				pos[top++] = pos[i] - 1;
		sort(pos, pos + top);
		memset(tree, -1, sizeof tree);
		for(int i=0; i<n; ++i)
		{
			int a = lower_bound(pos, pos + top, l[i]) - pos,
				b = lower_bound(pos, pos + top, r[i]) - pos;
			update(a, b, i, 0, top-1, 1);
		}
		bs.reset();
		query(0, top-1, 1);
		printf("%d\n", bs.count());
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值