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

来源:互联网 发布:淘宝信用卡手续费2017 编辑:程序博客网 时间:2024/05/16 06:47

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报。

思路:线段树直接做会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 10005using 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;}

原创粉丝点击