poj2528(线段树+离散化)Mayor's posters

2016-08-15

题意:一面墙,往上面贴海报,后面贴的可以覆盖前面贴的。问最后能看见几种海报。

思路:可以理解成往墙上涂颜色,最后能看见几种颜色(下面就是以涂色来讲的)。这面墙长度为1~1000 0000,一千万,确实很大。暴力的话肯定不行,除非..( you know)。

正确的解法是用线段树,不过还得加上离散化,因为数据太大10000000啊。

先说一下离散化,这个其实就是压缩,把范围压缩,举个例子:

输入 :

1 3000    //涂第一种颜色 范围从1~10000      下面同理

2000 7000  //第二种颜色

我们可以先把输入的数据范围压缩,假如输入的数据存到数组a[0]=1,a[1]=3000,a[2]=2000,a[3]=7000。

离散化(压缩)过程:

先把a[]从小到大排序。然后接着

把a数组里的数据映射到dis数组里,这样涂颜色(插入)的时候用dis[a[i]]。

压缩完之后建树的时候只需建1~4范围的树,而不用建1~7000的树。所以说离散化是必须的...懂嘞谬?

离散化完事后,再说说线段树,到底是个什么树呢?

比如1~10这个线段,用二叉树的形式储存起来,

看图:

然后在每个节点加上各种信息,就可以用了,虽然空间大了但时间快了

对于这个问题 线段树主要用了三个函数

void build(int p,int a,int b) //建树

void update(int p,int col,int a,int b)//插入颜色

void query(int p)  //查询颜色

代码有详细解释

AC代码:

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 using namespace std;
  6
  7 const int MAXN=10005;
  8
  9 bool tagcol[MAXN];   //标记颜色是否已经计算过
 10
 11 int e[MAXN<<1];     //临时数组,把重复的数据去掉
 12 int ee[MAXN][2];    //直接输入数据的数组 存每张海报的范围的
 13 int dis[10000001];   //离散化之后的映射数组
 14 int cnt=0;           //颜色计数器
 15
 16 struct node     //线段树节点
 17 {
 18     int l,r;    //l~r 范围
 19     int c;    //颜色(用1,2,3...表示)
 20 }LTnode[MAXN<<4];    //开数组的时候尽量开大点,开8倍就Runtime Error了,开16倍就过,虽然不知道为啥
 21
 22 void build(int p,int a,int b)   //建树,p是节点下标,范围 a~b
 23 {
 24     LTnode[p].l=a;
 25     LTnode[p].r=b;
 26     LTnode[p].c=0;
 27     if(a==b)    //到叶子节点直接返回
 28     {
 29         return;
 30     }
 31
 32     //继续递归建树
 33     int mid=(a+b)>>1;
 34     build(p<<1,a,mid);
 35     build(p<<1|1,mid+1,b);
 36     return;
 37 }
 38 void update(int p,int col,int a,int b)   //更新(插入)颜色,p是节点下标,col是颜色,a,b是要更新的范围
 39 {
 40     if(LTnode[p].l>=a&&LTnode[p].r<=b)   //如果当前节点范围 正好在a,b内,更新颜色 返回
 41     {
 42         LTnode[p].c=col;
 43         return;
 44     }
 45     if(LTnode[p].r<a||LTnode[p].l>b)   //如果当前节点范围和a,b没有交集
 46         return;
 47     if(LTnode[p].c>=0)   //当前节点和a,b有部分交集
 48     {
 49         LTnode[p<<1].c=LTnode[p<<1|1].c=LTnode[p].c;  //把当前节点的颜色传递给左右孩子节点,灰常重要
 50         LTnode[p].c=-1;    //-1代表有多种颜色
 51     }
 52     //继续处理左右孩子
 53     update(p<<1,col,a,b);
 54     update(p<<1|1,col,a,b);
 55     return;
 56 }
 57
 58 void query(int p)   //查询,p是节点下标
 59 {
 60     if(LTnode[p].c==0)  //当前节点的颜色为0,即没有颜色
 61         return;
 62     if(LTnode[p].c>0&&!tagcol[LTnode[p].c])  //当前节点有某种颜色并且该颜色没有被计算过
 63     {
 64         cnt++;  //颜色计数器+1
 65         tagcol[LTnode[p].c]=true;
 66         return;
 67     }
 68     if(LTnode[p].c==-1)  //多色 则继续细化处理左右孩子
 69     {
 70         query(p<<1);
 71         query(p<<1|1);
 72     }
 73     return;
 74
 75 }
 76
 77 int main()
 78 {
 79     int T;
 80     scanf("%d",&T);
 81     while(T--)
 82     {
 83
 84         memset(tagcol,false,sizeof(tagcol));
 85         memset(dis,0,sizeof(dis));
 86
 87         int n;   //n表示有几张海报
 88         //cin>>n;
 89         scanf("%d",&n);
 90         int maxp=0;
 91         for(int i=0;i<n;i++)
 92         {
 93             //cin>>ee[i][0]>>ee[i][1];
 94             scanf("%d%d",&ee[i][0],&ee[i][1]);  //poj上用scanf就过,cin就TLE 坑啊...
 95             if(!dis[ee[i][0]])   //用dis数组先标记下 有没有重复的数据 这样就不用再开一个数组了
 96             {
 97                 e[maxp++]=ee[i][0];
 98                 dis[ee[i][0]]=1;
 99             }
100             if(!dis[ee[i][1]])
101             {
102                 e[maxp++]=ee[i][1];
103                 dis[ee[i][1]]=1;
104             }
105         }
106         memset(dis,0,sizeof(dis));
107         int has=0;
108         sort(e,e+maxp);   //先排序
109         for(int i=0;i<maxp;i++)  //for循环出来后 has 就是离散后的最大范围
110         {
111             dis[e[i]]=++has;
112         }
113         build(1,1,has);
114         for(int i=0;i<n;i++)   //一次插入颜色,i为颜色
115         {
116             update(1,i+1,dis[ee[i][0]],dis[ee[i][1]]);
117         }
118         cnt=0;
119         query(1);
120         cout<<cnt<<endl;
121
122     }
123
124     return 0;
125 }

手打真累啊,肩膀疼..

poj2528(线段树+离散化)Mayor's posters

时间: 2024-08-11 01:23:01

poj2528(线段树+离散化)Mayor's posters的相关文章

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

[poj2528]Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 66154   Accepted: 19104 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their elect

poj2528 线段树+离散化

1 //Accepted 1960K 110MS 2 //线段树+离散化 3 //把所有的坐标排序,从小到大编号,建立线段树 4 #include <cstdio> 5 #include <cstring> 6 #include <iostream> 7 #include <queue> 8 #include <cmath> 9 #include <algorithm> 10 using namespace std; 11 /** 1

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

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

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

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

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

恩,这区间范围挺大的,需要离散化.如果TLE,还需要优化一下常数. AC代码 #include <stdio.h> #include <string.h> #include <map> #include <set> #include <algorithm> using namespace std; const int maxn = 40000+5; typedef pair<int, int> Pii; Pii a[10000 + 5

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 (线段树+离散化)

题目连接: http://poj.org/problem?id=2528 题目大意: 有10000000块瓷砖,n张海报需要贴在墙上,每张海报所占的宽度和瓷砖宽度一样,长度是瓷砖长度的整数倍,问按照所给海报顺序向瓷砖上贴海报,最后有几张海报是可见的? 解题思路: 因为瓷砖块数和海报张数多,首选线段树,如果按照常规的建树方式,把瓷砖当做数的节点,肯定会MTL......... 所以我们可以用海报的起点和终点当做树的节点,这样树的节点才有20000个,但是这样建树的话,求海报覆盖了那些节点会很复杂,

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

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