POJ_Mayor's Poster_线段树、离散化

来源:互联网 发布:租车软件排行 编辑:程序博客网 时间:2024/04/29 10:18

每次A题都要听一次小苹果,感觉自己萌萌哒。


题意:

一个线段上10^7个点可以“涂色”,每个点只能涂一种,后涂覆盖先涂,离线进行最多10^5次操作,每次区间涂一种新的颜色,最后求问一共有多少中颜色。(线段上本来无色)。



Input

The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers li and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= li <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered li, li+1 ,... , ri.

Output

For each input data set print the number of visible posters after all the posters are placed.


一开始在纠结10^5次涂色怎么更新树,后来看了题解也没提,然后才想起来离线操作只要向下更新就好了,不用回溯,反正最后遍历一遍整棵树就可以。。。。。

然后题解里提了我没想到的问题,线段长达10^7,空间开销很大,10^7个int需要32*10^7 / (8*1024)K,大概4*10^4K,题目给了6*10^4K,线段树肯定会MLE。由于线段树很大,也会脱慢速度,不过O(logn)的算法速度的影响应该还不是很大。

为了解决这个问题,要用离散化操作。离散化是把较大空间的点映射到一个较小的空间里去。具体操作就是先读入所有操作,把每个操作的l和r记录,去重,然后排序,重新编号,这样原来的空间就紧凑很多了。这道题这里有个问题,不能只离散化l和r两个点,要多加他们两端的两个点,否则会过度压缩,具体什么情况POJ的discuss里有,但是我没这么处理也过了,应该是数据水。。。总不能是标程出错了吧。

在离散化的过程中我的办法不是很好,看了下空间开销,我的是4*10^4多,和预估的一样,但是很多代码都是三次方级别的空间,想了想没想到什么好的办法,用map什么的存储pair然后用二分查找,那样常数大一点但是复杂度会降下去。


代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<cmath>#include<algorithm>using namespace std;#define mxn 20100#define mxl 10000010int ll[mxn<<2],rr[mxn<<2];int color[mxn<<2],flag[mxn<<2];int n,l[mxn],r[mxn];int mapp[mxl],dis[mxn];int hash;void build(int l,int r,int id){ll[id]=l,rr[id]=r,color[id]=-1,flag[id]=-1;if(l==r)return;int m=(l+r)>>1,ls=id<<1,rs=ls|1;build(l,m,ls);build(m+1,r,rs);}void down(int id);void update(int l,int r,int x,int id){if(ll[id]==l&&rr[id]==r){flag[id]=x;color[id]=x;return;}color[id]=-1;if(flag[id]!=-1)down(id);int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;if(r<=m)update(l,r,x,ls);else if(l>m)update(l,r,x,rs);else{update(l,m,x,ls);update(m+1,r,x,rs);}}void down(int id){if(ll[id]==rr[id])return;int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;update(ll[id],m,flag[id],ls);update(m+1,rr[id],flag[id],rs);flag[id]=-1;}void find(int id){if(color[id]!=-1){flag[color[id]]=1;return;}if(ll[id]==rr[id])return;int ls=id<<1,rs=ls|1;find(ls);find(rs);}int ans(){int ret=0;for(int i=0;i<n;++i)if(flag[i])++ret;return ret;}int main(){int cs;scanf("%d",&cs);while(cs--){scanf("%d",&n);memset(mapp,0,sizeof(mapp));for(int i=0;i<n;++i){scanf("%d%d",&l[i],&r[i]);dis[i*2]=l[i];//应多加两个点离散化,但是那样POJ过不过就不知道了dis[i*2+1]=r[i];}hash=0;sort(dis,dis+2*n);for(int i=0;i<2*n;++i)if(!mapp[dis[i]])mapp[dis[i]]=++hash;for(int i=0;i<n;++i){l[i]=mapp[l[i]];r[i]=mapp[r[i]];}build(1,hash,1);for(int i=0;i<n;++i)update(l[i],r[i],i,1);memset(flag,false,sizeof(flag));find(1);printf("%d\n",ans());}return 0;}


0 0