题意
对于一面长度为n的墙,有m块画板起点分别为a,b覆盖在墙上,问最后能看见多少个画板
思路
此题给定的n太大,直接进行线段树可能会爆空间时间 ,应进行离散化,但要注意离散化排序完若相邻两个数之间差为1,则无法正确区分出看到的画板,比如1 10,1 4,5 10 和1 10,1 4 ,6 10会被看成同一种情况,应在这种情况中间加入一个中间值
再进行线段树
代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e4+5;
int M,L,R,ans;
int a[N],b[N];//记录m个板
int g[N*8],tr[N*16],vis[N];//g用来存储各个点的排序并进行离散化
//tr用来存各个值,vis数组用来存该板子是否被访问过
void pushdown(int x){
if(tr[x]==-1)return;//该区间无板子;
tr[x<<1]=tr[x<<1|1]=tr[x];
tr[x]=-1;
}
void update(int l,int r,int k,int x){
if(L<=l&&r<=R){
tr[x]=k;
return;
}
pushdown(x);
int mid=l+r>>1;
if(L<=mid)update(l,mid,k,x<<1);
if(R>mid)update(mid+1,r,k,x<<1|1);
}
void query(int l,int r,int x){
if(tr[x]!=-1){
if(vis[tr[x]]==0)++ans;
vis[tr[x]]=1;
return ;
}
if(l==r)return;
int mid=l+r>>1;
query(l,mid,x<<1);
query(mid+1,r,x<<1|1);
}
int main(){
int t;
cin>>t;
while(t--){
cin>>M;
int cnt=0;
for(int i=1;i<=M;i++){
cin>>a[i]>>b[i];
g[cnt++]=a[i];
g[cnt++]=b[i];
}
sort(g,g+cnt);
int m=unique(g,g+cnt)-g;//m代表去重后的所有元素数量
int dnt=m;
for(int i=0;i<=dnt-1;i++){
if(g[i+1]-g[i]>1)g[m++]=g[i]+1;
}
sort(g,g+m);//重新构造递增序列
memset(tr,-1,sizeof tr);
memset(vis,0,sizeof vis);
for(int i=1;i<=M;i++){
L=lower_bound(g,g+m,a[i])-g;
R=lower_bound(g,g+m,b[i])-g;
update(0,m,i,1);
}
ans=0;
query(0,m,1);
cout<<ans<<endl;
}
}