思路
典型的区间染色问题。
离散化区间端点(注意非连续区间中间要加点隔开),就可以建线段树了。
倒序每一次询问,查看该区间是否被覆盖,如果没有就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; }