poj 2528(线段树+离散化) 市长的海报

http://poj.org/problem?id=2528

题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张

就是有的先贴的海报可能会被后贴的海报完全盖住,那就看不见了

这里就非常抽象的区间更新,墙的长度为建立线段树的总区间,每贴一张海报代表将这个区间的颜色涂为相应的,每张海报的颜色当然

都不相同,求最后又多少种颜色就行,但这里还要用到基础的离散化

离散化是把无限空间中无限的个体映射到有限的空间中去,以此提高算法的时空效率。

简单点说,假设区间长度有一亿甚至跟多,但是区间里具体的值却最多只用到了一百万,且不说能否开那么大的数组,也造成了

内存的浪费,所以用离散化来节省不必要的浪费

举这个题目的样例来说(前三个)

如果只是改变区间1 7    2 6    8 10的颜色,那么剩下的数字并没有用到

那么我们将这些数字排序,x[1]=1 x[2]=2 x[3]=6 x[4]=7 x[5]=8 x[6]=10

但是如果每个相邻的差值大于1的时候要插入一个数(就插入x[i]-1好了),

(如果不插的话

假设三张海报为: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)

插入后新的排序为x[1]=1 x[2]=2 x[3]=5 x[4]=6 x[5]=7 x[6]=8 x[7]=9 x[8]=10

然后以这个新的长度为8的数组区间建树就好

code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 struct point {
 7     int l,r;
 8     int mark,sum;
 9 };
10 point tree[10001*4*4],num[10001*4];
11 int ans,res[10001*4],visit[10001*4];
12 void build(int i,int left,int right)
13 {
14     tree[i].l=left,tree[i].r=right;
15     tree[i].mark=tree[i].sum=0;
16     if (left==right) return ;
17     int mid=(left+right)/2;
18     build(i*2,left,mid);
19     build(i*2+1,mid+1,right);
20 }
21 void update(int i,int left,int right,int val)
22 {
23     if (left<=tree[i].l&&tree[i].r<=right){tree[i].mark=tree[i].sum=val;return ;}
24     if (tree[i].mark)
25     {
26         tree[i*2].mark=tree[i*2+1].mark=tree[i].mark;
27         tree[i*2].sum=tree[i*2+1].sum=tree[i].mark;
28         tree[i].mark=0;
29     }
30     int mid=(tree[i].r+tree[i].l)/2;
31     if (left>mid) update(i*2+1,left,right,val);
32     else if (right<=mid) update(i*2,left,right,val);
33     else
34     {
35         update(i*2,left,mid,val);
36         update(i*2+1,mid+1,right,val);
37     }
38 }
39 int find(int i)
40 {
41     if (tree[i].l==tree[i].r)
42     {
43         if (!visit[tree[i].sum])
44         {
45            visit[tree[i].sum]=1;
46            ++ans;
47         }
48         return ans;
49     }
50     if (tree[i].mark)
51     {
52         tree[i*2].mark=tree[i*2+1].mark=tree[i].mark;
53         tree[i*2].sum=tree[i*2+1].sum=tree[i].mark;
54         tree[i].mark=0;
55     }
56     find(i*2);
57     find(i*2+1);
58 }
59 int main()
60 {
61     int t,i,n,tn,tn1,powr,powl;
62     scanf("%d",&t);
63
64         if (t==0) return 0;
65         while (t--)
66         {
67             res[0]=0;
68             scanf("%d",&n);
69             for (i=1;i<=n;i++)
70             {
71                scanf("%d %d",&num[i].l,&num[i].r);
72                if (num[i].l>num[i].r) swap(num[i].l,num[i].r);
73                res[++res[0]]=num[i].l;
74                res[++res[0]]=num[i].r;
75             }
76             sort(res+1,res+res[0]+1);  离散化
77             tn1=tn=unique(res+1,res+res[0]+1)-res;
78             for (i=2;i<tn;i++)//插入数
79                if (res[i]-res[i-1]>1)
80                   res[tn1++]=res[i]-1;
81             res[0]=tn1-1;
82             sort(res+1,res+res[0]+1);
83             build(1,1,res[0]);//以新的区间建树
84             for (i=1;i<=n;i++)
85             {
86                 powl=lower_bound(res+1,res+1+res[0],num[i].l)-res;
87                 powr=lower_bound(res+1,res+1+res[0],num[i].r)-res;
88                 update(1,powl,powr,i);
89             }
90             ans=0;
91             memset(visit,0,sizeof(visit));
92             visit[0]=1;
93             printf("%d\n",find(1));
94         }
95
96     return 0;
97 }
时间: 2024-11-05 17:31:48

poj 2528(线段树+离散化) 市长的海报的相关文章

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

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9

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

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 86160   Accepted: 24734 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 线段树+离散化

题意是给你n张海报,告诉你每张海报的宽度和先后顺序,海报会重叠,问你露在外面的海报有多少张?这题主要是离散化理解了好久,关键在于建hash表时不能选择最普通的一一对应,为什么?看了网上一组数据后瞬间就明白了:1,10  1,4  6,10. Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 51347   Accepted: 14875 Description The citizens of

Mayor&#39;s posters POJ - 2528 线段树区间覆盖

//线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=100010; int flag; struct node{ int l,r; //vis 是这块区域是否完全被覆盖 bool vis; }tr[N<<2]; struct point { int id; int x

poj 2528 线段树+特殊离散化

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 51098   Accepted: 14788 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 线段树+延迟更新

题目链接:http://poj.org/problem?id=2528 题意: 在墙上贴海报,输入n(1<=n<=10000),表示n张海报,后n行输入 两整数l,r  ( 1<= l, r<= 1e9 ),表示海报从编号为l的石头一直贴到编号为r的石头,输入顺序即为粘贴顺序.问n张贴完之后,还能看到多少张海报. 思路: 显然区间操作,很容易联想到线段树操作,只不过区间 l,r 最大范围可达1e9,直接建树,内存必爆.   那么就需要避开1e9的数据,进行离散化,将区间变成(1到n

Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长

参考  https://www.cnblogs.com/null00/archive/2012/04/22/2464876.html #include <stdio.h> #include <algorithm> #define LEN 10000 using namespace std; struct Node { int left; int right; int count;//被覆盖次数 //所包含的区间数量,如三条[1,2],[2,3],[4,5]线段被覆盖,则line=2

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

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

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