poj 2528 Mayor’s posters 【离散化】+【线段树】

<题目链接>

题目大意:

往一堵墙上贴海报,依次输出这些海报张贴的范围,这些海报能够相互覆盖,问最后能够看见几张海报?

解题分析:

由于是给出每张海报的区间,所以在这些区间内的很多点可能用不上,所以我们采用离散化,将这个大的区间映射到一个更小更紧凑的区间。

但是只是这样简单的离散化是错误的, 如三张海报为: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

poj 2528 Mayor’s posters 【离散化】+【线段树】的相关文章

POJ 2528 Mayor&#39;s posters(离散化线段树)

Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for

POJ 2528 Mayor&#39;s posters(离散化 线段树)

题意  在墙上贴n张海报  输入每张海报的的左右端点坐标  问最后可以看到多少张海报  能看到一点也是能看到 先把线段树初始化为0 输入一张海报  就把那个区间变成这张海报的序号  最后判断墙上有多少个不同的序号就行了 但是海报坐标的端点值高达10000000  直接用线段树会超时   但是注意到海报最多只有10000张  也就是最多有20000个不同的坐标  于是可以利用离散化的知识   把所有坐标排序 注意所有右端点坐标+1也要加入排序(注意1,10 ; 1,3;  7,10这种情况  如果

POJ - 2528 - Mayor&#39;s posters 【线段树+离散化+补点】

http://poj.org/problem?id=2528 #include <cstdio> #include <iostream> #include <set> #include <cstring> #include <string> #define left rt<<1 #define right rt<<1|1 using namespace std; const int MAXN = 32768 + 5; in

POJ 2528 Mayor&#39;s posters(线段树+离散化)

题目链接:Mayor's posters 题意:按顺序往墙上贴海报,可以重叠,问最后可以看到多少海报.(被覆盖的海报是看不到的) 注意: 因为数据比较大,所以不离散化,肯定爆内存. 还有就是,不能只是单纯的离散化,还要处理好点的边界 举个例子 4 2  10. 2  8 3  6 6  8 8  10 离散化后 2 3 6 8 10 1 2 3 4 5 覆盖掉了 1 5   和  1 4俩段 只剩下 2  3  .3  4. 4  5 答案是 3 但是正确答案是4 所以,离散化处理时要处理边界,

【POJ】2528 Mayor&#39;s posters ——离散化+线段树

Mayor's posters Time Limit: 1000MS    Memory Limit: 65536K Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city

POJ 2528 Mayor&#39;s posters(线段树区间染色+离散化或倒序更新)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 59239   Accepted: 17157 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

poj(2528)——Mayor&#39;s posters(线段树+离散化)

这道题目让我又重新认识了一下离散化: 首先总结一下离散化的特点: 1)有时区间的端点并不是整数,或者区间太大导致建树内存开销过大而MLE,那么就需要进行离散化后再建树. 2)意思是将区间范围很大的数据集映射到较小的数据集,这样建树更加有效,或者说我们只取需要的值来用. 这个意思说到底就是进行映射,把原来很大的映射到一个较小的空间中去. 题意: 给定一些海报,它们可能相互重叠,告诉你每个海报的宽度(它们的高度都是一样的)和先后的叠放次序,问没有被完全盖住的海报有多少张? 这里我们注意到了数据的范围

poj 2528 Mayor&#39;s posters 【线段树 + 离散化】

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 50643   Accepted: 14675 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

POJ - 2528 Mayor&#39;s posters (线段树+离散化)

Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for

poj 2528 Mayor&#39;s posters(线段树 离散化 区间更新 贴海报)

     这个题目本来对大神来说可能是水题, 对我就不行了,昨晚非折腾到下半夜一点 搞定, 并且可以总结出 ,只有把问题想清楚,或着看人家解题报告自己把问题和代码思路 搞清楚,才能谈的上调bug,否则根本就不知道错在哪儿.说说这个题目的理解,他是如何转化为线段树问题的呢?我们知道线段树有一个区间更新的东西,每张海报的宽度不就是一个区间么?那么我们可以用一棵树中的部分结点 来表示整张海报的可视部分,也就是说每个结点只允许表示一张完整的或着不完整的海报(好几个结点才可以表示成完整的一张海报),那么如