题意:一维的墙上,n个人去贴海报,海报覆盖一定的区间,后贴的可能覆盖先贴的,问最后能看到多少张海报。
思路:线段树(区间更新)+离散化。因为墙的范围太大,n的范围小,所以需要离散化。离散化时注意如果两点不连续,需要在中间插入一个点,不然会出现bug。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#define ll long long
using namespace std;
int pl[20010];
int pr[20010];
int post[40010];
struct node{
int l; int r;
int val;
bool flag;
};
node tree[160010];
void build_tree(int n,int l,int r){
tree[n].l=l; tree[n].r=r; tree[n].flag=0;
if(l==r)return;
int mid=(l+r)/2;
build_tree(n*2,l,mid);
build_tree(n*2+1,mid+1,r);
}
void update(int n,int l,int r,int v){
if(tree[n].l==l&&tree[n].r==r){
tree[n].val=v; tree[n].flag=1;
return;
}
int mid=(tree[n].l+tree[n].r)/2;
if(tree[n].flag){
tree[n].flag=0;
update(n*2,tree[n].l,mid,tree[n].val);
update(n*2+1,mid+1,tree[n].r,tree[n].val);
}
if(r<=mid){
update(n*2,l,r,v);
}else{
if(l<=mid){
update(n*2,l,mid,v);
update(n*2+1,mid+1,r,v);
}else{
update(n*2+1,l,r,v);
}
}
}
void query(int n,int l,int r){
if(tree[n].flag){
post[tree[n].val]=1;
return;
}
if(l==r)return;
int mid=(l+r)/2;
query(n*2,l,mid);
query(n*2+1,mid+1,r);
}
map<int,int> mp;
int main(){
int t;
cin>>t;
while(t--){
memset(post,0,sizeof(post));
mp.clear();
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d%d",&pl[i],&pr[i]);
mp[pl[i]]=1;
mp[pr[i]]=1;
}
int cnt=1;
map<int,int>::iterator last=mp.begin();
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){
if(last!=it&&last->first+1<it->first)cnt++;//在不连续的点中间插入点,防止中间点被忽略
it->second=cnt++;
last=it;
}
build_tree(1,1,cnt-1);
for(int i=1;i<=n;i++){
update(1,mp[pl[i]],mp[pr[i]],i);
}
query(1,1,cnt-1);
int ans=0;
for(int i=1;i<cnt;i++)if(post[i])ans++;
cout<<ans<<endl;
}
return 0;
}