思路
典型的区间染色问题。
离散化区间端点(注意非连续区间中间要加点隔开),就可以建线段树了。
倒序每一次询问,查看该区间是否被覆盖,如果没有就ans++,然后顺便把区间覆盖掉。
代码
#include<iostream>
#include<vector>
#include<algorithm>
#define MID int mid=(p->l + p->r)>>1
using namespace std;
struct Post{ // 海报
int l,r;
} pst[10100];
int nodenum,cnt,ans;
int t,n,hs[10000010];
vector<int>vt;
struct Node{
int l,r;
bool full; // 区间[l,r]是否被完全覆盖
Node *ls, *rs;
}tr[1000000];
void buildTree(Node *p, int l, int r){ //建树
p->l=l;
p->r=r;
p->full=0; //初始化节点
if(l==r)return; //如果是叶子,直接返回
nodenum++;
p->ls=tr+nodenum; //建立左右子树
nodenum++;
p->rs=tr+nodenum;
MID;
buildTree(p->ls,l,mid); //左区间建树
buildTree(p->rs,mid+1,r); //右区间建树
}
bool check(Node *p,int l,int r){ //判断该区间是否有覆盖
if (p->full) return false; //已经被覆盖了,这份海报就看不到了
if (p->l==l&&p->r==r){
p->full=1; //覆盖此区间
return true;
}
bool res;
MID;
if(r<=mid) res=check(p->ls,l,r); //全在左区间,找左子树
else if(l>mid) res=check(p->rs,l,r);
else{
bool b1=check(p->ls,l,mid);
bool b2=check(p->rs,mid+1,r);
res=b1||b2; //其中一点没覆盖即可
}
if (p->ls->full&&p->rs->full){
p->full=1;//如果左右区间都被覆盖,那么这个区间也被覆盖了
}
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n;
nodenum=0,cnt=0,ans=0; //清空数据
for(int i=0;i<n;i++) {
cin>>pst[i].l>>pst[i].r;
vt.push_back(pst[i].l); //把区间端点放入容器
vt.push_back(pst[i].r);
}
sort(vt.begin(),vt.end());//排序
vt.erase(unique(vt.begin(),vt.end()),vt.end()); //去重
for(int i=0;i<vt.size();i++){
hs[vt[i]]=cnt++; //记录元素所在数的节点编号
if(i<vt.size()-1){
if(vt[i+1]-vt[i]>1) cnt++; //中间再插一个点
}
}
buildTree(tr,0,cnt);//开始建树
for(int i=n-1;i>=0;i--){ //这里倒序,要从没被覆盖的开始数
if(check(tr,hs[pst[i].l],hs[pst[i].r])){
ans++; //可见海报增加
}
}
cout<<ans<<endl;
}
return 0;
}
京公网安备 11010502036488号