题目
-
题目链接:http://poj.org/problem?id=2528
-
题意:第一行T:测试用例数量;第二行n,海报的数目;接下来n行,l, r,:【l, r】区间被一张海报覆盖;问最终能看到多少的海报
思路
- 典型的线段树,区间覆盖。不过这里(l, r)的最大值是1千万, built(1, 一千万, 1), 肯定会超时,要将坐标离散化;
-
离散化:
比如原题测试样例n张海报区间时:
(1, 4), (2, 6), (8, 10), (3, 4), (7, 11);
- 离散化处理完成后就是常规的区间覆盖了
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200005;
bool vis[maxn];
int LL[maxn], RR[maxn];
int x[maxn << 2];
int cnt;
struct{
int l, r;
int num;//num表示海报 num>0表示【l,r】区间被海报num覆盖,num==-1表示【l,r】有超过两种海报
}tree[maxn << 2];
int lower_bound(int l, int r, int key){//二分查找下标,最后的离散化数组与原来的实际上是下标对应关系,原来的值对应离散在新数组中的值的下标
int mid = (l + r) / 2;
if(x[mid] == key) return mid;
else if(key < x[mid]) return lower_bound(l, mid - 1, key);
else return lower_bound(mid + 1, r, key);
}
void built(int s, int e, int node){
tree[node].l = s;
tree[node].r = e;
tree[node].num = 1;
int mid = (s + e) >> 1;
if(s == e){
return ;
}
built(s, mid, node << 1);
built(mid + 1, e, node << 1 | 1);
}
void update(int L, int R, int node, int num){
if(tree[node].l >= L && tree[node].r <= R){
tree[node].num = num;
return ;
}else{
if(tree[node].num != -1){//lazy的pushdown操作
tree[node << 1].num = tree[node].num;
tree[node << 1 | 1].num = tree[node].num;
tree[node].num = -1;
}
int mid = (tree[node].l + tree[node].r) >> 1;
if(mid < L) update(L, R, node << 1 | 1, num);
else if(mid >= R) update(L, R, node << 1, num);
else{
update(mid | 1, R, node << 1 | 1, num);
update(L, mid, node << 1, num);
}
}
}
void query(int L, int R, int node){
if(tree[node].num != -1){
vis[tree[node].num] = true;//【l, r】间的tree[node].num!=-1,说明这个区间都是一种海报,否则向下查找
return;
}else{
int mid = (tree[node].l + tree[node].r) >> 1;
if(L > mid){
query(L, R, node << 1 | 1);
}else if(R <= mid){
query(L, R, node << 1);
}else{
query(L, mid, node << 1);
query(mid + 1, R, node << 1 | 1);
}
}
}
int main(){
int t;
cin >> t;
while(t --){
memset(vis, false, sizeof(vis));
int ans = 0, n, cnt = 0;
cin >> n;
for(int i = 0; i < n; i++){
scanf("%d %d", &LL[i], &RR[i]);
x[++cnt] = LL[i];
x[++cnt] = RR[i];
}
sort(x + 1, x + cnt + 1);
// for(int i = 1; i <= cnt; i++){
// cout << "x[" << i << "]= " << x[i] << endl;
// }
//去重
int count = 1;
for(int i = 2; i <= cnt; i++){
if(x[i - 1] == x[i]){
while(x[i - 1] == x[i]){
i++;
}
i--;
}else{
x[++count] = x[i];
}
}
// for(int i = 1; i <= count; i++){
// cout << "x[" << i << "]= " << x[i] << endl;
// }
//不能让不是领居的变成邻居,正确的离散处理
cnt = count;
for(int i = 2; i <= count; i++){
if(x[i] - x[i - 1] > 1) x[++ cnt] = x[i - 1] + 1;
}
count = cnt;
sort(x + 1, x + count + 1);
// for(int i = 1; i <= count; i++){
// cout << "x[" << i << "]= " << x[i] << endl;
// }
built(1, count, 1);
for(int i = 0; i < n; i++){
int l = lower_bound(1, count, LL[i]);
int r = lower_bound(1, count, RR[i]);
//cout << l << r << endl;
//区间覆盖
update(l, r, 1, i + 1);
}
//查询
query(1, count, 1);
for(int i = 1; i <= n; i++){
if(vis[i]) ans ++;
}
cout << ans << endl;
}
//cin >> t;
return 0;
}
版权声明:本文为qq_44744457原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。