题目链接:https://vjudge.net/problem/POJ-2528
这道题问我们最后能看到多少张海报,如果正着想会比较麻烦,因为我们不确定当前的海报是否会被之后的海报所掩盖,但是我们可以肯定的是之后的海报一定不会被他之前的海报所掩盖,所以我们就可以倒着来贴海报,如果当前贴的海报能被看见,说明不会被之后的海报所遮挡,至于怎么查询是否被遮挡,这就是线段树的区间查询问题了。由于题目给的海报的边界比较大,数组无法直接存下,我们只需要存储他们的相对大小关系即可,所以我们需要用到离散化。
但是离散化时需要注意一些问题,比如三个区间:
1 10
1 4
6 10
答案显然是3,但是我们离散化后变成:
1 4
1 2
3 4
这样答案就变成2了,那这是为什么呢?
原本第2张海报和第三张海报之间是有间隔的,但是我们离散化后他们就变成相邻的了,于是如果有一张大海报包括他们的间隔,那么对答案就会造成影响,所以我们对于离散化之前不相邻的数之间加一个中间值,这样就可以消除这种影响,但是由于这道题目的数据比较水,即使不考虑这种情况也可以ac,但还是希望大家能够考虑到这种情况,毕竟下次遇到的题目数据就不一定那么水了。下面上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
vector<int>alls;
const int N=5e6+10;
int ll[N],rr[N],l[N],r[N],sum[N],lazy[N];
int find(int x)
{
return (lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1);
}
void pushup(int id)
{
sum[id]=sum[id<<1]+sum[id<<1|1];
}
void pushdown(int id)
{
if(lazy[id])
{
lazy[id<<1]=lazy[id];
lazy[id<<1|1]=lazy[id];
sum[id<<1]=(r[id<<1]-l[id<<1]+1)*lazy[id];
sum[id<<1|1]=(r[id<<1|1]-l[id<<1|1]+1)*lazy[id];
lazy[id]=0;
}
}
void build(int id,int L,int R)
{
l[id]=L;r[id]=R;sum[id]=0;lazy[id]=0;
if(L==R) return ;
int mid=L+R>>1;
build(id<<1,L,mid);
build(id<<1|1,mid+1,R);
pushup(id);
}
void update_interval(int id,int L,int R,int val)
{
if(l[id]>=L&&r[id]<=R)
{
sum[id]=(r[id]-l[id]+1)*val;
lazy[id]=val;
return ;
}
pushdown(id);
int mid=l[id]+r[id]>>1;
if(mid>=L) update_interval(id<<1,L,R,val);
if(mid+1<=R) update_interval(id<<1|1,L,R,val);
pushup(id);
return ;
}
int query_interval(int id,int L,int R)
{
if(l[id]>=L&&r[id]<=R) return sum[id];
pushdown(id);
int mid=l[id]+r[id]>>1;
int ans=0;
if(mid>=L) ans+=query_interval(id<<1,L,R);
if(mid+1<=R) ans+=query_interval(id<<1|1,L,R);
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
alls.clear();
scanf("%d",&n);
build(1,1,4*n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ll[i],&rr[i]);
alls.push_back(ll[i]);
alls.push_back(rr[i]);
}
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
int len=alls.size();
//在离散化数组中相邻两个间隔大于1的数之间加一个中间值来消除间隔的影响
for(int i=1;i<len;i++)
if(alls[i]-alls[i-1]>1)
alls.push_back(alls[i-1]+1);
sort(alls.begin(),alls.end());//排序
alls.erase(unique(alls.begin(),alls.end()),alls.end());//去重
int ans=0;
for(int i=n;i>=1;i--)
{
int l1=find(ll[i]),r1=find(rr[i]);
if(query_interval(1,l1,r1)!=r1-l1+1)
{
ans++;
update_interval(1,l1,r1,1);
}
}
printf("%d\n",ans);
}
return 0;
}