POJ 2528 解题报告

这道题一开始没想清楚做法,后面突然想通后又感觉很自然。

首先是离散化。由于区间端点的范围太大,所以需要“离散化”,亦即把所有出现的端点排个序,按照他们出现的位置重新编号,这样每个端点的值改成了其大小位置编号,范围瞬间减少了非常多,差不多成了输入的线段数两倍。这时应该可以按照最naive的做法,即把这个范围内的数标记,看覆盖没有做出回答了。但我自己没这么尝试过。

其次是问题的题意理解。比如1 4值得是占据了第一个到第四个区间。再比如有个输入段是5 10那么他们就覆盖了1 10段,因为确实所有的区间都被覆盖了。如果第二个输入段是6 10,那么就不能覆盖1 10段了。这样离散化的时候需要注意:可以把1, 4, 5, 10离散化成0, 1, 2, 3但是不能把1, 4, 6, 10也离散化成0, 1, 2, 3,不然后者会导致错误判断。一个离散化的方法是如果和前面的值连续的,就加1,否则,像6出现在4后面,这样的值离散化成加2。具体见代码实现或者里面给出的链接。看discuss,另一个方法是直接对右端点加1。

然后是线段树的update和query,其实比较难弄清楚,我也是在测试样例的基础上面不断改的。

下面的测试样例:

8
3
5 6
4 5
6 8
3
1 10
1 3
6 10
3
1 10
1 3
6 10
4
2 4
3 5
1 3
5 7
5
1 11
11 11
5 66
7 88
8 110
5
1 4
2 6
8 10
3 4
7 10
5
1 4
2 6
8 10
3 4
7 10
11
1 8
4 6
5 8
2 3
1 5
2 5
6 8
1 3
2 5
4 5
3 4

输出应该是:

2
3
3
3
4
4
4
5

刚开始用的“延迟”update,后面发现根本不需要,如果一个段需要更新,找到合适的区间后就不用向下更新到叶子节点了,因为查找的时候发现这段已经被covered了,也就不用往下看是不是covered了。

2528Accepted1504K63MSG++4981B
/* 
ID: thestor1 
LANG: C++ 
TASK: poj2528 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

const int MAXN = 25000;

class Poster{
public:
	int left, right;
	Poster() {}
	Poster(int left, int right) : left(left), right(right) {}
};

class Position
{
public:
	int posterid, pos;
	bool isleft;
	Position() {}
	Position(int posterid, int pos, bool isleft) : posterid(posterid), pos(pos), isleft(isleft) {}

	bool operator< (const Position &rhs) const
	{
		if (this->pos != rhs.pos)
		{
			return this->pos < rhs.pos;
		}
		return this->posterid < rhs.posterid;
	}
};

// class Segment
// {
// public:
// 	bool covered, delay;
// 	Segment() : covered(false), delay(false) {}
// 	Segment(bool covered, bool delay) : covered(covered), delay(delay) {}
// };

void update(vector<bool> &segmentTree, int left, int right, int index, const int lindex, const int rindex)
{
	if (segmentTree[index])
	{
		return;
	}

	if (lindex <= left && right <= rindex)
	{
		segmentTree[index] = true;
		return;
	}

	if (left != right)
	{
		int mid = left + ((right - left) >> 1);
		if (rindex <= mid)
		{
			update(segmentTree, left, mid, 2 * index + 1, lindex, rindex);	
		}
		else if (mid + 1 <= lindex)
		{
			update(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);	
		}
		else
		{
			update(segmentTree, left, mid, 2 * index + 1, lindex, rindex);
			update(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);
		}
		segmentTree[index] = segmentTree[2 * index + 1] && segmentTree[2 * index + 2];
	}
}

bool querycovered(vector<bool> &segmentTree, int left, int right, int index, const int lindex, const int rindex)
{	
	if (segmentTree[index])
	{
		return true;
	}

	if (lindex <= left && right <= rindex)
	{
		return segmentTree[index];
	}

	if (left != right)
	{
		int mid = left + ((right - left) >> 1);
		if (rindex <= mid)
		{
			return querycovered(segmentTree, left, mid, 2 * index + 1, lindex, rindex);
		}
		else if (mid + 1 <= lindex)
		{
			return querycovered(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);
		}
		else
		{
			return querycovered(segmentTree, left, mid, 2 * index + 1, lindex, rindex) && querycovered(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);	
		}
	}

	assert (false);
	return false;
}

int main()
{
	// ios::sync_with_stdio(false);
	int T;
	// cin >> T;
	scanf("%d", &T);
	int N;
	vector<Poster> posters(MAXN);
	vector<Position> positions(2 * MAXN);
	vector<bool> segmentTree(9 * MAXN);

	for (int t = 0; t < T; ++t)
	{
		// cin >> N;
		scanf("%d", &N);
		for (int i = 0; i < N; ++i)
		{
			scanf("%d%d", &posters[i].left, &posters[i].right);
			// cin >> posters[i].left >> posters[i].right;
			// positions.push_back(Position(i, posters[i].left, true));
			// positions.push_back(Position(i, posters[i].right, false));
			// positions[2 * i] = Position(i, posters[i].left, true);
			// positions[2 * i + 1] = Position(i, posters[i].right, false);
			positions[2 * i].posterid = i;
			positions[2 * i].pos = posters[i].left;
			positions[2 * i].isleft = true;

			positions[2 * i + 1].posterid = i;
			positions[2 * i + 1].pos = posters[i].right;
			positions[2 * i + 1].isleft = false;
		}

		// compress the coordinates
		sort(positions.begin(), positions.begin() + 2 * N);

		int seqno = 0, before = positions[0].pos, cur;
		for (int i = 0; i < 2 * N; ++i)
		{
			if (positions[i].isleft)
			{
				cur = posters[positions[i].posterid].left;
				// see http://blog.csdn.net/metalseed/article/details/8041334 for reason why
				// basically, for segments like, 1->4, 6->10 and 1->10
				// you want mark that 1->10 is not totally covered by the previous two segments,
				// therefore, you leave space between 4 and 6
				if (cur == before + 1)
				{
					seqno++;
				}
				else if (cur > before + 1)
				{
					seqno += 2;
				}
				posters[positions[i].posterid].left = seqno;
			}
			else
			{
				cur = posters[positions[i].posterid].right;
				if (cur == before + 1)
				{
					seqno++;
				}
				else if (cur > before + 1)
				{
					seqno += 2;
				}

				posters[positions[i].posterid].right = seqno;
			}
			before = cur;
		}

		int size = seqno + 1;
		for (int i = 0; i < 4 * size; ++i)
		{
			segmentTree[i] = false;
		}
		int nvisible = 0;
		for (int i = N - 1; i >= 0; --i)
		{
			if(!querycovered(segmentTree, 0, size - 1, 0, posters[i].left, posters[i].right))
			{
				nvisible++;
				update(segmentTree, 0, size - 1, 0, posters[i].left, posters[i].right);
			}
		}

		printf("%d\n", nvisible);
		// cout << nvisible << endl;
	}
	return 0;  
}



2528Accepted1916K79MSG++5733B

/* 
ID: thestor1 
LANG: C++ 
TASK: poj2528 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

const int MAXN = 25000;

class Poster{
public:
	int left, right;
	Poster() {}
	Poster(int left, int right) : left(left), right(right) {}
};

class Position
{
public:
	int posterid, pos;
	bool isleft;
	Position() {}
	Position(int posterid, int pos, bool isleft) : posterid(posterid), pos(pos), isleft(isleft) {}

	bool operator< (const Position &rhs) const
	{
		if (this->pos != rhs.pos)
		{
			return this->pos < rhs.pos;
		}
		return this->posterid < rhs.posterid;
	}
};

class Segment
{
public:
	bool covered, delay;
	Segment() : covered(false), delay(false) {}
	Segment(bool covered, bool delay) : covered(covered), delay(delay) {}
};

void update(vector<Segment> &segmentTree, int left, int right, int index, const int lindex, const int rindex)
{
	if (segmentTree[index].covered)
	{
		return;
	}

	if (lindex <= left && right <= rindex)
	{
		segmentTree[index].covered = true;
		if (left != right)
		{
			segmentTree[index].delay = true;
		}
		return;
	}

	if (left != right)
	{
		assert (!segmentTree[index].delay);
		// if (segmentTree[index].delay)
		// {
		// 	segmentTree[2 * index + 1].covered = true;
		// 	segmentTree[2 * index + 1].delay = true;
		// 	segmentTree[2 * index + 2].covered = true;
		// 	segmentTree[2 * index + 2].delay = true;
		// 	segmentTree[index].delay = false;
		// }

		int mid = left + ((right - left) >> 1);
		if (rindex <= mid)
		{
			update(segmentTree, left, mid, 2 * index + 1, lindex, rindex);	
		}
		else if (mid + 1 <= lindex)
		{
			update(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);	
		}
		else
		{
			update(segmentTree, left, mid, 2 * index + 1, lindex, rindex);
			update(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);
		}
		segmentTree[index].covered = segmentTree[2 * index + 1].covered && segmentTree[2 * index + 2].covered;
	}
}

bool querycovered(vector<Segment> &segmentTree, int left, int right, int index, const int lindex, const int rindex)
{	
	if (segmentTree[index].covered)
	{
		return true;
	}

	if (lindex <= left && right <= rindex)
	{
		return segmentTree[index].covered;
	}

	if (left != right)
	{
		if (segmentTree[index].delay)
		{
			segmentTree[2 * index + 1].covered = true;
			segmentTree[2 * index + 1].delay = true;
			segmentTree[2 * index + 2].covered = true;
			segmentTree[2 * index + 2].delay = true;
			segmentTree[index].delay = false;
		}

		int mid = left + ((right - left) >> 1);
		if (rindex <= mid)
		{
			return querycovered(segmentTree, left, mid, 2 * index + 1, lindex, rindex);
		}
		else if (mid + 1 <= lindex)
		{
			return querycovered(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);
		}
		else
		{
			return querycovered(segmentTree, left, mid, 2 * index + 1, lindex, rindex) && querycovered(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex);	
		}
	}

	assert (false);
	return false;
}

int main()
{
	// ios::sync_with_stdio(false);
	int T;
	// cin >> T;
	scanf("%d", &T);
	int N;
	vector<Poster> posters(MAXN);
	vector<Position> positions(2 * MAXN);
	vector<Segment> segmentTree(9 * MAXN);

	for (int t = 0; t < T; ++t)
	{
		// cin >> N;
		scanf("%d", &N);
		for (int i = 0; i < N; ++i)
		{
			scanf("%d%d", &posters[i].left, &posters[i].right);
			// cin >> posters[i].left >> posters[i].right;
			// positions.push_back(Position(i, posters[i].left, true));
			// positions.push_back(Position(i, posters[i].right, false));
			// positions[2 * i] = Position(i, posters[i].left, true);
			// positions[2 * i + 1] = Position(i, posters[i].right, false);
			positions[2 * i].posterid = i;
			positions[2 * i].pos = posters[i].left;
			positions[2 * i].isleft = true;

			positions[2 * i + 1].posterid = i;
			positions[2 * i + 1].pos = posters[i].right;
			positions[2 * i + 1].isleft = false;
		}

		// compress the coordinates
		sort(positions.begin(), positions.begin() + 2 * N);

		int seqno = 0, before = positions[0].pos, cur;
		for (int i = 0; i < 2 * N; ++i)
		{
			if (positions[i].isleft)
			{
				cur = posters[positions[i].posterid].left;
				// see http://blog.csdn.net/metalseed/article/details/8041334 for reason why
				// basically, for segments like, 1->4, 6->10 and 1->10
				// you want mark that 1->10 is not totally covered by the previous two segments,
				// therefore, you leave space between 4 and 6
				if (cur == before + 1)
				{
					seqno++;
				}
				else if (cur > before + 1)
				{
					seqno += 2;
				}
				posters[positions[i].posterid].left = seqno;
			}
			else
			{
				cur = posters[positions[i].posterid].right;
				if (cur == before + 1)
				{
					seqno++;
				}
				else if (cur > before + 1)
				{
					seqno += 2;
				}

				posters[positions[i].posterid].right = seqno;
			}
			before = cur;
		}

		int size = seqno + 1;
		for (int i = 0; i < 4 * size; ++i)
		{
			segmentTree[i].covered = false;
			segmentTree[i].delay = false;
		}
		int nvisible = 0;
		for (int i = N - 1; i >= 0; --i)
		{
			if(!querycovered(segmentTree, 0, size - 1, 0, posters[i].left, posters[i].right))
			{
				nvisible++;
				update(segmentTree, 0, size - 1, 0, posters[i].left, posters[i].right);
			}
		}

		printf("%d\n", nvisible);
		// cout << nvisible << endl;
	}
	return 0;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值