【题目链接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=14608
[解题报告】
题目大意:
给定长度区间(L,R)//L,R<=1e7,
给出N个区间操作,把li-ri区间贴上海报 //N《=1e5
求:有多少张海报没有被完全覆盖
这道题目的关键在于,直接开1e7的线段树一定会MLE,但我们观察到一共只有不超过1e5张海报,如果每张海报我们只取它的两个端点,只对它的端点进行处理,空间复杂度就会大大降低。
所以如何处理呢?
比如区间[1,4],[5,6]有四个不同端点,说明我们需要把他映射到线段树上四个不同的位置。
我们从1开始对线段树的叶子节点进行标记,那么映射到的相对应的线段树区间为:
[1,4]->[1,2]
[5,6]->[3,4]
这时候出现一个问题:
我们先后贴上[1,10],[1,4],[5,10],映射为:[1,4],[1,2],[3,4]只能看见两张海报
如果先后贴上[1,10],[1,4],[7,10],映射为:[1,4],[1,2],[3,4],只能看见两张海报。
哪里出了问题?
问题在于:
如果两条相邻线段并不相交,离散化之后,它变成了相交!
所以维护这样的性质:如果两个顶点并不紧邻,那么我们离散化之后,它们仍然不能紧邻。方法是在两个顶点之间再插入一个顶点。
到了这里,大部分问题就解决了。
还需要思考一个问题:如何查找没有被完全覆盖的海报的数目。
容易想到,我们更新的时候,给区间(l,r)打上标记i表示当前位置的海报是i,这样最后统计有多少个不同的i即可。
为了不重复查询相同的,没有被完全覆盖的i,如: (1,10),( 3,4 ),(7,8)更新之后的标记就是1,2,1,3,1,会出现多个第1张海报的标记,我们需要单独设置一个hash数组,如果某张海报已经被统计过了,就不再重复统计。
这样,剩下的就是线段树模板的内容了。
剩下的细节可以参考代码。我的线段树风格参考刘汝佳的《训练指南》。
【参考代码】
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+50;
int N,m,cnt;
int l[maxn],r[maxn],vis[maxn],X[maxn];
int cover[maxn*4];
void uniq( int nn )
{
m=0;
X[++m]=X[1];
for( int i=2; i<=nn; i++ )
{
if( X[i]!=X[i-1] )X[++m]=X[i];
}
sort( X+1,X+1+m );
int t=m;
for( int i=1;iif( X[i]!=X[i+1]-1 )X[++m]=X[i]+1;
}
sort( X+1,X+1+m );
}
void build( int O, int L, int R )
{
if(L==R)cover[O]=-1;
else
{
int mid=(L+R)/2;
build(O*2+1,mid+1,R );
build( O*2,L,mid );
cover[O]=-1;
}
}
void pushdown( int O )
{
if( cover[O]!=-1 )
{
cover[O*2]=cover[O*2+1]=cover[O];
cover[O]=-1;
}
}
void update( int O, int L, int R, int qL, int qR, int c )
{
if( qL<=L && R<=qR )
{
cover[O]=c;
}
else
{
pushdown( O );
int mid=(L+R)/2;
if( qL<=mid )update( O*2,L,mid, qL,qR,c );
if( qR>mid )update( O*2+1, mid+1,R,qL,qR,c );
}
}
void query( int O, int L, int R )
{
if( L==R )
{
if( cover[O]!=-1 && !vis[cover[O]] )
{
vis[cover[O]]=1;
cnt++;
}
}
else
{
pushdown(O);
int mid=(L+R)/2;
query( O*2, L,mid );
query( O*2+1,mid+1,R );
}
}
int main()
{
//freopen("2528","r",stdin);
int T; cin>>T;
while(T--)
{
scanf( "%d",&N );
int nn=0;
for( int i=1; i<=N; i++ )
{
scanf( "%d%d",&l[i],&r[i] );
X[++nn]=l[i]; X[++nn]=r[i];
}
sort( X+1,X+1+nn );
uniq(nn);
build( 1,1,m );
for( int i=1; i<=N; i++ )
{
int left=lower_bound( X+1,X+1+m,l[i] )-X;
int right=lower_bound( X+1,X+1+m,r[i] )-X;
update( 1,1,m,left,right,i );
}
memset( vis,0,sizeof vis );
cnt=0;
query( 1,1,m );
printf( "%d\n",cnt );
}
return 0;
}