【题目大意】
有一块长度为x的板(1<=x<=10000000)均分成x份,每份长一个单位长度。现在有n张海报(1<=n<=10000),每张海报有个区间[li,ri],表示这张海报会占用[li,ri]的位置,若区间[li,ri]有其他海报,那么这些海报会被新贴的覆盖,按照输入的顺序贴这n张海报。问最后能看见多少张海报。(同一张海报由于被覆盖分成多段只算一张)
【解题思路】
由于li,lr很大,但海报的数量相对来说是比较小的。
所以把海报的区间离散化。
后贴的海报会覆盖前面的海报。
所以我们从后面“贴“起。
从后面"贴"起,例如贴第i张,若区间内还有空位那么最终显示出来的海报i。
对于第i张海报,若区间[li,ri]还有空位,那么ans+1
用线段树维护即可。
【代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
bool sym;
struct data
{
int v,num;
}b[101010];
int a[101010];
int ans;
bool cmp(data x,data y)
{
return (x.v<y.v);
}
bool tree[101010];
void update(int l,int r,int L,int R,int root)
{
if (r<L || l>R) return;
if (l>=L && r<=R)
{
tree[root]=false;
return;
}
if (!tree[root]) return;
int mid=(l+r)/2;
update(l,mid,L,R,root*2);
update(mid+1,r,L,R,root*2+1);
tree[root]=tree[root*2] | tree[root*2+1];
}
void query(int l,int r,int L,int R,int root)
{
if (r<L || l>R) return;
if (l>=L && r<=R)
{
sym=sym | tree[root];
return;
}
if (!tree[root]) return;
int mid=(l+r)/2;
query(l,mid,L,R,root*2);
query(mid+1,r,L,R,root*2+1);
tree[root]=tree[root*2] | tree[root*2+1];
}
int main()
{
freopen("e.in","r",stdin);
freopen("e.out","w",stdout);
int T;
scanf("%d",&T);
while (T--)
{
memset(tree,true,sizeof(tree));
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&b[i].v,&b[i+n].v);
b[i].num=i;
b[i+n].num=i+n;
}
sort(b+1,b+n+n+1,cmp);
int nbr=0;
for (int i=1;i<=2*n;i++)
{
if (b[i].v!=b[i-1].v) nbr++;
a[b[i].num]=nbr;
}
ans=0;
for (int i=n;i>=1;i--)
{
sym=false;
query(1,nbr,a[i],a[i+n],1);
if (sym) ans++;
update(1,nbr,a[i],a[i+n],1);
}
printf("%d\n",ans);
}
}