每次A题都要听一次小苹果,感觉自己萌萌哒。
题意:
一个线段上10^7个点可以“涂色”,每个点只能涂一种,后涂覆盖先涂,离线进行最多10^5次操作,每次区间涂一种新的颜色,最后求问一共有多少中颜色。(线段上本来无色)。
Input
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 10000010
int 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;
}