题目链接
题目大意
其实就不是不停的张贴海报,可能后面的海报可以把前面的海报覆盖,求最后能看到多少张海报(只要没有被全部覆盖就算可以看见)
题目思路
此题是线段树区间覆盖问题,显然数据过大,故要离散化。还有此题根本没有必要进行建树的操作,最开始都是0。
易错警示
1:此题有一个坑点。如 1,10 1,4 7,10 这三组数的正确结果应该是还以看到3种颜色,但是如果直接排列点的话就会挤掉5到6这一
种颜色。所以离散的时候可以离散a,a+1,a-1,b,b-1,b+1就不会出现这种情况。
2:本题我多次re,故再次总结re的常见原因。数组越界,多次递归爆栈,除0模0会造成re,而我是询问的时候只询问了一半的区间
而可能那半边区间正好没有return的结果就会一直递归,然后到最后才截至。
3:数组大小不只是4e5,因为有a,b两个数组,故应该最少是8e5,但是离散所要用的数组又是6e5,开大一点没错
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=24e5+5;
int t,n,i,j=1,temp[maxn],vis[maxn],ans,a[maxn],b[maxn],tree[maxn];
void updown(int node)//相当于把自己当作懒标记
{
tree[node<<1]=tree[node<<1|1]=tree[node];
tree[node]=0;
return ;
}
void update(int node,int l,int r,int L,int R,int k)//小写l,r是要修改的范围,大写L,R是node的范围
{
if(l<=L&&r>=R)
{
tree[node]=k;
return ;
}
if(tree[node])
updown(node);//懒标记
int mid=(L+R)>>1;
if(mid>=l) update(node<<1,l,r,L,mid,k);
if(mid<r) update(node<<1|1,l,r,mid+1,R,k);
return ;
}
void query(int node,int l,int r)
{
if(l==r&&tree[node]==0)
{
return ;
}
if(tree[node])
{
vis[tree[node]]=1;
return ;
}
int mid=(l+r)/2;
query(node<<1,l,mid);
query(node<<1|1,mid+1,r);
return ;
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(tree,0,sizeof(tree));//清零
memset(vis,0,sizeof(vis));
j=1;
ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d %d",&a[i],&b[i]);
temp[j++]=a[i];//离散要用的数组
temp[j++]=b[i];
temp[j++]=a[i]-1;
temp[j++]=a[i]-1;
temp[j++]=b[i]+1;
temp[j++]=b[i]+1;
}
sort(temp+1,temp+1+6*n);//为离散做准备
int cnt=unique(temp+1,temp+1+6*n)-temp-1;//找出不重复的数的个数
for(i=1;i<=n;i++)//离散化
{
a[i]=lower_bound(temp+1,temp+1+cnt,a[i])-temp;
b[i]=lower_bound(temp+1,temp+1+cnt,b[i])-temp;
update(1,a[i],b[i],1,6*n+1,i);//更新线段树,最后一个参数表示染的颜色
}
query(1,1,6*n+1);//询问
for(i=1;i<=6*n+1;i++)
{
if(vis[i]) ans++;
}
printf("%d\n",ans);
}
return 0;
}
如有错误,欢迎指正