Problem:poj.org/problem?id=2528
参考:blog.youkuaiyun.com/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;
}