这道题一开始没想清楚做法,后面突然想通后又感觉很自然。
首先是离散化。由于区间端点的范围太大,所以需要“离散化”,亦即把所有出现的端点排个序,按照他们出现的位置重新编号,这样每个端点的值改成了其大小位置编号,范围瞬间减少了非常多,差不多成了输入的线段数两倍。这时应该可以按照最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了。
2528 | Accepted | 1504K | 63MS | G++ | 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;
}
2528 | Accepted | 1916K | 79MS | G++ | 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;
}