<题目链接>
题目大意:
往一堵墙上贴海报,依次输出这些海报张贴的范围,这些海报能够相互覆盖,问最后能够看见几张海报?
解题分析:
由于是给出每张海报的区间,所以在这些区间内的很多点可能用不上,所以我们采用离散化,将这个大的区间映射到一个更小更紧凑的区间。
但是只是这样简单的离散化是错误的, 如三张海报为:1~10 1~4 6~10 离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10 第一张海报时:墙的1~4被染为1; 第二张海报时:墙的1~2被染为2,3~4仍为1; 第三张海报时:墙的3~4被染为3,1~2仍为2。 最终,第一张海报就显示被完全覆盖了,于是输出2,但实际上明显不是这样,正确输出为3。 新的离散方法为:在相差大于1的数间加一个数,例如在上面1 4 6 10中间加5(算法中实际上1,4之间,6,10之间都新增了数的) X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 5, X[ 4 ] = 6, X[ 5 ] = 10 这样之后,第一次是1~5被染成1;第二次1~2被染成2;第三次4~5被染成3 最终,1~2为2,3为1,4~5为3,于是输出正确结果3。
这是我的WA代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <set> 5 6 using namespace std; 7 typedef long long ll; 8 const int M =2*10000+10; 9 #define Lson rt<<1,l,mid 10 #define Rson rt<<1|1,mid+1,r 11 set<int>s; 12 struct Seg{ 13 ll le,ri; 14 }seg[M<<4]; 15 16 ll tr[M<<4],lazy[M<<4],res[M<<4]; 17 18 void Pushdown(int rt,int len){ 19 if(lazy[rt]){ 20 lazy[rt<<1]=lazy[rt]; 21 lazy[rt<<1|1]=lazy[rt]; 22 tr[rt<<1]=tr[rt]; 23 tr[rt<<1|1]=tr[rt]; 24 lazy[rt]=0; 25 } 26 } 27 28 void update(int rt,int l,int r,int L,int R,int c){ 29 if(L<=l&&r<=R){ 30 lazy[rt]=c,tr[rt]=c; 31 return; 32 } 33 Pushdown(rt,r-l+1); 34 int mid=(l+r)>>1; 35 if(L<=mid)update(Lson,L,R,c); 36 if(R>mid)update(Rson,L,R,c); 37 38 void query(int rt,int l,int r){ 39 if(l==r){ 40 s.insert(tr[rt]); 41 return; 42 } 43 Pushdown(rt,r-l+1); 44 int mid=(l+r)>>1; 45 query(Lson); 46 query(Rson); 47 } 48 49 int main(){ 50 int T;scanf("%d",&T); 51 while(T--){ 52 int cnt=0; 53 s.clear(); 54 int n;scanf("%d",&n); 55 memset(tr,0,sizeof(tr)); 56 memset(lazy,0,sizeof(lazy)); 57 for(int i=1;i<=n;i++){ 58 scanf("%lld%lld",&seg[i].le,&seg[i].ri); 59 res[++cnt]=seg[i].le; 60 res[++cnt]=seg[i].ri; 61 } 62 sort(res+1,res+1+cnt); 63 int num=1; 64 for(int i=2;i<=cnt;i++) 65 if(res[i]!=res[i-1]) 66 res[++num]=res[i];//去重 67 for(int i=num;i>=2;i--){ 68 if(res[i]-res[i-1]>1)res[++num]=res[i]-1; 69 } 70 sort(res+1,res+1+num); 71 for(int i=1;i<=n;i++){ 72 int left=lower_bound(res+1,res+1+num,seg[i].le)-res; 73 int right=lower_bound(res+1,res+1+num,seg[i].ri)-res; 74 update(1,1,num,left,right,i); 75 } 76 query(1,1,num); 77 printf("%d\n",s.size()); 78 } 79 return 0; 80 }
这是AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 7 #define Lson rt<<1,l,mid 8 #define Rson rt<<1|1,mid+1,r 9 const int maxn=10000+100; 10 int x[maxn<<4],tr[maxn<<4],lx[maxn<<2],rx[maxn<<2]; 11 set<int>s; 12 13 void Pushdown(int rt){ 14 tr[rt<<1]=tr[rt<<1|1]=tr[rt]; 15 tr[rt]=-1; 16 } 17 18 void update(int rt,int l,int r,int L,int R,int c){ 19 if(L<=l&&r<=R){ 20 tr[rt]=c; 21 return; 22 } 23 if(tr[rt]!=-1)Pushdown(rt); //如果tr[rt]==-1,说明不需要将该点的值Pushdown 24 int mid=(l+r)>>1; 25 if(L<=mid)update(Lson,L,R,c); 26 if(R>mid)update(Rson,L,R,c); 27 } 28 29 void query(int rt,int l,int r){ 30 if(tr[rt]!=-1){ //因为update的时候,只要该节点的区间包含在要求修改的区间内,就直接将值赋给该节点了,不会继续向下更新,所以,不用一直查询到子节点 31 s.insert(tr[rt]); //用set来去掉重复的标号 32 return; 33 } 34 if(l==r)return; 35 if(tr[rt]!=-1)Pushdown(rt); 36 int mid=(l+r)>>1; 37 query(Lson); 38 query(Rson); 39 } 40 41 int main(){ 42 int T;scanf("%d",&T); 43 while(T--){ 44 memset(tr,-1,sizeof(tr)); 45 int cnt=0; 46 int n;scanf("%d",&n); 47 s.clear(); 48 for(int i=1;i<=n;i++){ 49 scanf("%d%d",&lx[i],&rx[i]); 50 x[++cnt]=lx[i]; 51 x[++cnt]=rx[i]; 52 } 53 sort(x+1,x+1+cnt); 54 int num=1; 55 for(int i=2;i<=cnt;i++){ 56 if(x[i]!=x[i-1])x[++num]=x[i]; //去重 57 } 58 for(int i=num;i>=2;i--){ 59 if(x[i]-x[i-1]>1)x[++num]=x[i]-1; //如果两个点之间间距>1,那么在它们之间插入一个点 60 } 61 sort(x+1,x+1+num); 62 for(int i=1;i<=n;i++){ 63 int le=lower_bound(x+1,x+1+num,lx[i])-x; //找到该点离散化后的坐标 64 int ri=lower_bound(x+1,x+1+num,rx[i])-x; 65 update(1,1,num,le,ri,i); //将这段区间染成 i 66 } 67 query(1,1,num); //查找整个离散化后的区域总共有多少种标号 68 printf("%d\n",s.size()); 69 } 70 return 0; 71 }
2018-09-22
原文地址:https://www.cnblogs.com/00isok/p/9690345.html
时间: 2024-08-22 11:34:35