您的位置:首页 > 其它

POJ 2528 & UVA 10587(线段树+离散+区间修改)

2013-08-05 16:53 309 查看
题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报。

思路:线段树直接做会TLE+MLE,因此需要离散。所谓离散就是将区段进行压缩,但是又不改变区间的位置关系。

方法就是将区段的端点值去掉相同的进行排序,举个例子:

给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。

现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9

然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9

对其升序排序,得2 3 4 6 8 9 10

然后建立映射

2 3 4 6 8 9 10

↓ ↓ ↓ ↓ ↓ ↓ ↓

1 2 3 4 5 6 7

那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。

而这题的难点在于每个数字其实表示的是一个单位长度(并非一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱)

给出下面两个简单的例子应该能体现普通离散化的缺陷:

例子一:1-10 1-4 5-10

例子二:1-10 1-4 6-10

普通离散化后都变成了[1,4][1,2][3,4]

线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?

例子一是完全被覆盖掉了,而例子二没有被覆盖为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]

如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define M ((L+R)>>1)
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls,L,M
#define rson rs,M+1,R
#define MAXN 10005
using namespace std;

int Ft[MAXN*2],F[MAXN*3],setv[MAXN*15];//F[]作为最终映射 Ft[]作为临时映射需要处理后放入F[]
bool vis[MAXN];
int Li[MAXN],Ri[MAXN],n,T,fn;
int yl,yr,ans,v;

void pushdown(int o,int L,int R) {if(setv[o]>=0) {setv[ls]=setv[rs]=setv[o];setv[o]=-1;}}
void update(int o,int L,int R)
{
if(yl<=L && R<=yr) {setv[o]=v;return;}
pushdown(o,L,R);
if(yl<=M) update(lson);
if(M<yr) update(rson);
}
void query(int o,int L,int R)
{
if(setv[o]>=0)
{
if(!vis[setv[o]]) vis[setv[o]]=1,++ans;
return;
}
if(L==R) return;
if(1<=M) query(lson);
if(M<fn-1) query(rson);
}
int main()
{
scanf("%d",&T);
while(T-- && scanf("%d",&n))
{
int nn=0;
for(int i=0;i<n;++i) {scanf("%d%d",&Li[i],&Ri[i]);Ft[nn++]=Li[i];Ft[nn++]=Ri[i];}
sort(Ft,Ft+nn);
F[1]=Ft[0],fn=2;
for(int i=1;i<nn;++i)
if(Ft[i]!=Ft[i-1])
{
if(Ft[i]-Ft[i-1]>1) F[fn++]=Ft[i-1]+1;
F[fn++]=Ft[i];
}
memset(vis,0,sizeof(vis));
memset(setv,-1,sizeof(setv));
for(v=0;v<n;++v)
{
yl=lower_bound(F+1,F+fn,Li[v])-F,yr=lower_bound(F+1,F+fn,Ri[v])-F;
update(1,1,fn-1);
}
ans=0;
query(1,1,fn-1);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: