题意:
大意就是在一个好长好长(10^7)的墙上贴好多好多(10^4)海报;
海报相互覆盖,求最后能看见多少海报;
题解:
这题给出一个这样的一个墙,显然是要维护一个数据结构嘛;
比如用线段树维护这样子的区间更新(笑);
但是10^7大小我们就这么开一个树必然不行;
所以离散化是必要的;
(我就会这么离散化怎样!)
然后机智的我用了并查集!想看码线段树的失望吧!
把所以区间离线下来,倒序覆盖,这样每个点仅维护一次就可以完成;
f[i]维护这个点后下一个的没有覆盖的点;
用并查集路径压缩f[i];
然后记录海报个数就不是问题了吧;
复杂度大概是O(n)吧。。。总之常数不小但也63ms水过;
//实际上这道题当然也可以线段树做,不过另一道“疯狂的馒头”就不行了,所以我只是想复习一下这样的算法(笑)
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 10001
using namespace std;
int f[N<<2],L[N],R[N],dis[N<<4];
bool vis[N];
int cmp(int a,int b)
{
return a<b;
}
int Find(int x)
{
return f[x]==x?x:f[x]=Find(f[x]);
}
int main()
{
int c,T,n,m,i,j,k,l,r,len,ans;
scanf("%d",&T);
for(c=1;c<=T;c++)
{
if(c!=1)
{
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
}
ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",L+i,R+i);
dis[((i-1)<<2)+1]=L[i]-1;
dis[((i-1)<<2)+2]=L[i];
dis[((i-1)<<2)+3]=R[i];
dis[((i-1)<<2)+4]=R[i]+1;
}
sort(dis+1,dis+(n<<2)+1,cmp);
len=unique(dis+1,dis+(n<<2)+1)-dis-1;
for(i=1;i<=len+1;i++)
{
f[i]=i;
}
for(i=n;i>0;i--)
{
l=lower_bound(dis+1,dis+len+1,L[i])-dis;
r=lower_bound(dis+1,dis+len+1,R[i])-dis;
for(j=Find(l);j<=r;j=Find(++j))
{
f[j]=Find(j+1);
if(vis[i]==0)
{
vis[i]++;
ans++;
}
}
}
printf("%d\n",ans);
}
}