大意为给定一堆海报张贴顺序与张贴区间,求最后有几张海报没完全被挡住(来啊互相伤害啊!)。
由于数据太大而且海报都是几个点连在一起的,用以前的思路开树过于浪费,于是我们先将数据离散化(大概就是将一段连续的cut成一个点)再开线段树,由于我们写的是当一片区域没有完全cover的时候s++并且将其cober,所以注意cover的时候从后往前
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 10005
int cut[10000005],ml[maxn],mr[maxn],mm[maxn*2];
struct tr
{
int l,r,cover;
}tree[maxn*8];
void build(int i,int ll,int rr)
{
tree[i].l=ll;
tree[i].r=rr;
tree[i].cover=0;
if(ll==rr) return;
build(i*2,ll,(ll+rr)/2);
build(i*2+1,(ll+rr)/2+1,rr);
}
int covered(int i,int ll,int rr)
{
if(tree[i].cover==1) return 0;
int res;
if(tree[i].l==ll&&tree[i].r==rr) {tree[i].cover=1;return 1;}
else if(ll>(tree[i].r+tree[i].l)/2) res=covered(i*2+1,ll,rr);
else if(rr<=(tree[i].r+tree[i].l)/2) res=covered(i*2,ll,rr);
else
{
int a=covered(i*2+1,(tree[i].r+tree[i].l)/2+1,rr);
int b=covered(i*2,ll,(tree[i].r+tree[i].l)/2);
if(a==1||b==1) res=1;
}
if(tree[i*2].cover==1&&tree[i*2+1].cover==1) tree[i].cover=1; //向上合并
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,i,k=0,s=0;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d%d",&ml[i],&mr[i]);
for(i=1;i<=n;i++) {mm[++k]=ml[i];mm[++k]=mr[i];}
sort(mm+1,mm+k+1);
k=unique(mm+1,mm+1+k)-mm-1; //将数据排序并减去重复的
for(i=1;i<=k;i++) cut[mm[i]]=i; //离散化
build(1,1,k);
for(i=n;i>=1;i--) {s+=covered(1,cut[ml[i]],cut[mr[i]]);}
printf("%d\n",s);
}
return 0;
}