题意:
一个无限长的板子,然后依次往上面贴n张和板子等高的海报,问你最后能看到多少张海报(漏出来就算)
思路:
https://www.cnblogs.com/xuejianye/p/5694750.html
线段树区间更新问题,但是要注意,给的长度的可能非常大,有1e9,不加处理直接维护一个线段树肯定会MLE,TLE,但是我们注意到一共最多只有2e4个点,因此我们可以用离散化的思想先对区间进行预处理,所谓的离散化,
将一个很大的区间映射为一个很小的区间,而不改变原有的大小覆盖关系,但是注意简单的离散化可能
会出现错误,给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 ,1-4, 5-10
例子二:1-10 ,1-4, 6-10
普通离散化后都变成了[1,4],[1,2],[3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖
解决的办法则是对于距离大于1的两相邻点,中间再插入一个点。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson root<<1, l, mid
#define rson root<<1|1, mid+1, r
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 10000+50;
int ans, Tree[maxn<<3], L[maxn], R[maxn], tmp[maxn<<2];
bool vis[maxn<<2];
void push_down(int root){
if(Tree[root] == 0) return;
Tree[root<<1] = Tree[root<<1|1] = Tree[root];
Tree[root] = 0;
}
void update(int la, int rb, int l, int r, int root, int val){
if(la > r||l > rb) return;
if(la <= l&&rb >= r){
Tree[root] = val;
return;
}
push_down(root);
int mid = (l+r) >> 1;
if(la <= mid)
update(la, rb, l, mid, root<<1, val);
if(rb > mid)
update(la, rb, mid+1, r, root<<1|1, val);
}
void Query(int root, int l, int r){
if(Tree[root]){
if(!vis[Tree[root]]){
++ans;
vis[Tree[root]] = true;
}
return;
}
if(l == r) return;
push_down(root);
int mid = (l+r) >> 1;
Query(lson);
Query(rson);
}
int main()
{
//freopen("in.txt","r",stdin);
int T, n; scanf("%d",&T);
while(T--){
scanf("%d",&n);
memset(Tree, 0, sizeof(Tree));
int len = 0;
for(int i = 1; i <= n; ++i){
scanf("%d%d",&L[i],&R[i]);
tmp[len++] = L[i];
tmp[len++] = R[i];
}
// 离散化
sort(tmp, tmp+len);
len = unique(tmp, tmp+len) - tmp;
int m = len;
for(int i = 0; i < m-1; ++i){
if(tmp[i+1] - tmp[i] > 1) tmp[len++] = tmp[i] + 1;
}
sort(tmp, tmp+len);
for(int i = 1; i <= n; ++i){
int a = lower_bound(tmp, tmp+len, L[i]) - tmp+1;
int b = lower_bound(tmp, tmp+len, R[i]) - tmp+1;
update(a, b, 1, len, 1, i);
}
ans = 0;
memset(vis, 0, sizeof(vis));
Query(1, 1, len);
printf("%d\n", ans);
}
fclose(stdin);
return 0;
}