POJ 2528 ——Mayor's posters(线段树+区间操作)
Time limit | 1000 ms |
Memory limit | 65536 kB |
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 placing the posters and introduce the following rules:
- Every candidate can place exactly one poster on the wall.
- All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in Bytetown).
- The wall is divided into segments and the width of each segment is one byte.
- Each poster must completely cover a contiguous number of wall segments.
They have built a wall 10000000 bytes long (such that there is enough place for all candidates). When the electoral campaign was restarted, the candidates were placing their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in Bytetown was curious whose posters will be visible (entirely or in part) on the last day before elections.
Your task is to find the number of visible posters when all the posters are placed given the information about posters' size, their place and order of placement on the electoral wall.
Input
The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers l i and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= l i <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered l i, l i+1 ,... , ri.
Output
For each input data set print the number of visible posters after all the posters are placed.
The picture below illustrates the case of the sample input.
(图片上传失败了,呜呜呜)
Sample Input
1
5
1 4
2 6
8 10
3 4
7 10
Sample Output
4
题目分析
题目要求在一个长为1000,0000的墙上贴海报,但是后面贴上的海报可以覆盖原来已经有了的海报,求贴上一定数量的海报后,还有多少张海报可以被看见(只需要有一小部分可以看见即可,不需要完全看见)。
首先看到这个题,先被这个长度为1000w的墙吓到了,这要是像平时那样直接用这个区间来建树的话,会不会暴内存呀!对于这一点看了别人的写法后,发现他们都对这个区间进行了压缩(似乎叫做离散化),具体做法就是对每个区间的端点进行排序,将小的端点放在前面,这样一来不仅让我们用了建树的区间缩小到了80w,而且还不改变这些报纸所在区间的相对位置,这个方法很值得记下来,嗯。
说了一个优化空间的方法,但是没有解决这个题目的算法还是无法AC(这个说法似乎有点傻......),那么对于这个题,我们肯定是使用线段树来写的,而且还需要进行线段树的区间更新,而我们需要在每一个区间内维护的信息则是这个区间内有哪一张海报,用flag记录海报的序号(因为海报是按照输入顺序贴上墙壁的),对于有多个海报同时存在的区间,这个区间的flag = 0,所以,每贴一张海报,我们就需要更新一次这张海报所占的区间的flag。
现在具体讲一下代码的具体实现情况(也可以说是线段树区间更新的原理):
每贴一张海报我们就更新一次这张海报所占的区间,用尽量大的区间来表示这张海报所占的区间,这样可以用最少的区间来表示要修改的区间,这也是线段树为什么运算速度快的原有,对于这些用来表示海报所占用区间的区间,他们的整个区间上肯定是这张海报所在的区间,所以将这个区间的flag记作这张海报的编号(只对这个区间的flag进行标记,而不对其子区间)。
当下一张海报开始更新的时候,更新到了某一个区间[nl,nr],如果这个区间完全处在这张海报所在的区间内,那么直接将这个区间的flag设置为这张海报即可(当然,如果这个区间原来的flag != 0 ,那么就相当于直接覆盖原来的,然后这个区间的海报只有现在这张海报);
而如果这个区间并不完全处于这个海报所在的区间内,而且这个区间的flag != 0 ,也就是之前的海报完全覆盖了这个区间,并且新的海报有一部分处于这个区间内,这样的话,就说明这个区间同时存在了两种海报,这样的话我们就需要将这个区间原来的flag 分配给其左右区间——因为这个区间不完全属于新的海报,又因为这个区间不是完全处于这个海报所在的区间内,所以要寻找这个区间的子区间,直到这个区间的某几个子区间可以表示这张海报所在的区间为止
因为要访问当前区间的子区间,而且左右区间是即将访问的区间,所以在访问当前区间的左右区间之前(可能访问),我们需要将属于这个区间的flag分配给其左右区间,而将自己的flag归零(这里flag就是相当于lazy的存在,也就是没有将整个区间的flag分配下去,而是在即将访问某个区间之前将需要访问区间应有的flag从其当前区间分配下来,这个地方就是线段树区间更新的精髓所在,我理解为对线段树的单点更新使用线段树),这样一来,不仅让当前区间的flag = 0 , 表示当前区间没有完全处在单独一张海报之下,而且将左右区间的flag分配了下去,这样就让没有被当前海报覆盖的区间的flag仍保持原来的flag
通过以上的方式就可以保证flag != 0 的区间完全包含某一种海报,而且flag的值就代表海报的编号(这里采用的是海报的输入顺序作为编号)
最后,我们只需要对每一个区间进行查询,判断某一个区间是否完全包含某一种海报,并用vis[x]记录海报x的出现。
在这里,我把线段树的区间更新的原理讲了一遍,可能讲的很不好,但我希望能对各位有所帮助。
代码区
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<sstream>
#include <iterator>
#include<cmath>
#include <map>
#define sf(a) scanf("%d",&a)
#define sff(a,b) scanf("%d%d",&a,&b)
#define sfff(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sffff(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define slf(a) scanf("%lld",&a)
#define ssf(str) scanf("%s",str)
#define scf(ch) scanf("%c",&ch)
#define mem(s,data) memset(s,data,sizeof(s))
#define forL(i,a, b) for (int i = a; i <= b; i++)
#define forL(j,a, b) for (int j = a; j <= b; j++)
#define forR(i,a, b) for (int i = a; i >= b; i--)
#define forR(j,a, b) for (int j = a; j >= b; j--)
#define ltree(num) num<<1
#define rtree(num) num<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int max2 = + ;
const int max3 = + ;
const int max4 = + ;
const int max5 = + ;
const int max6 = + ;
typedef long long ll; struct Node
{
int l;
int r;
int flag; //记录这个区间中含有第几张海报
}node[*max4]; //区间大小为2*max4左右,所以结点的最大编号为其四倍(听大神说,这样可以不越界) bool vis[ * max4]; //vis[x]记录海报x是否可见 //初始化压缩后的区间
void build(int nl,int nr,int num)
{
node[num].l = nl;
node[num].r = nr;
node[num].flag = ;
if (nl == nr)
return;
const int mid = (nl + nr) >> ;
build(nl, mid, num << );
build(mid + , nr, num << | );
} //将这个区间的海报分配给下一个要查询的区间
void flag_release(int num)
{
if(node[num].flag)
{
node[num << ].flag = node[num << | ].flag = node[num].flag;
node[num].flag = ;
}
} void upData(int fl,int fr,int id,int num) //[fl,fr]代表海报所占区间(可能是子区间),id表示是第几张海报,num是当前区间的编号
{
if(fl <= node[num].l && node[num].r <= fr) //当前区间完全落在查询区间内,就是找到尽量大的区间来表示查询区间
{
node[num].flag = id; //记录这个区间代表的海报是第几个
return;
}
flag_release(num);
const int mid = node[num].l + ((node[num].r - node[num].l) >> );
if (fl <= mid) upData(fl, fr, id, num << ); //需要更新的区间有在当前区间的左区间的部分
if (fr > mid) upData(fl, fr, id, num << | ); //需要更新的区间有在当前区间的右区间的部分
} void query(int num)
{
if ((node[num].l == node[num].r) || node[num].flag) //叶子节点或者整个区间均在某一张海报之下
{
vis[node[num].flag] = true; //如果这个叶子结点可以看见海报,也就是flag != 0,那么就说明这个海报出现了
//否则只会将vis[0]改为true,意味着墙上还有空位
return;
}
const int mid = (node[num].l + node[num].r) >> ;
query( num<<);
query( num << | ); //查找所有区间
} int main()
{
int t;
scanf("%d", &t);
while(t--)
{
mem(vis, ); //初始化目前没有海报可见,毕竟海报还没有贴上去
int k;
scanf("%d", &k);
int tx[max4], ty[max4]; //记录各个海报的位置
int n = ; //记录压缩后的区间的长度
int a[*max4]; //记录各个区间端点
for (int i = ; i <= k;i++)
{
scanf("%d%d", tx + i, ty + i);
a[n++] = *(tx + i);
a[n++] = *(ty + i);
}
sort(a, a + n);
//区间压缩
for (int i = ; i <= k;i++)
{
tx[i] = (lower_bound(a, a + n, tx[i]) - a) + ;
ty[i] = (lower_bound(a, a + n, ty[i]) - a) + ;
} build(, n, ); //建树并初始化
for(int i = ; i <= k ; i++)
{
upData(tx[i], ty[i], i, ); //加上第i张海报后的更新
}
query(); //访问所有的区间,查看海报的出现情况
int sum = ;
for(int i = ; i <= k ; i++)
{
if (vis[i])
sum++;
}
cout << sum << endl;
}
return ;
}
POJ 2528 ——Mayor's posters(线段树+区间操作)的更多相关文章
- POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化)
POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化) 题意分析 贴海报,新的海报能覆盖在旧的海报上面,最后贴完了,求问能看见几张海报. 最多有10000张海报,海报 ...
- POJ 2528 Mayor's posters (线段树区间更新+离散化)
题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值 ...
- poj 2528 Mayor's posters 线段树区间更新
Mayor's posters Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=2528 Descript ...
- POJ 2528 Mayor's posters(线段树,区间覆盖,单点查询)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 45703 Accepted: 13239 ...
- POJ 2528 Mayor's posters (线段树+区间覆盖+离散化)
题意: 一共有n张海报, 按次序贴在墙上, 后贴的海报可以覆盖先贴的海报, 问一共有多少种海报出现过. 题解: 因为长度最大可以达到1e7, 但是最多只有2e4的区间个数,并且最后只是统计能看见的不同 ...
- poj 2528 Mayor's posters 线段树+离散化技巧
poj 2528 Mayor's posters 题目链接: http://poj.org/problem?id=2528 思路: 线段树+离散化技巧(这里的离散化需要注意一下啊,题目数据弱看不出来) ...
- POJ 2528 Mayor's posters(线段树+离散化)
Mayor's posters 转载自:http://blog.csdn.net/winddreams/article/details/38443761 [题目链接]Mayor's posters [ ...
- poj 2528 Mayor's posters 线段树+离散化 || hihocode #1079 离散化
Mayor's posters Description The citizens of Bytetown, AB, could not stand that the candidates in the ...
- poj 2528 Mayor's posters(线段树)
题目:http://poj.org/problem?id=2528 题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的, 但是必定是单位宽度的整数 ...
- POJ 2528 Mayor's posters (线段树)
题目链接:http://poj.org/problem?id=2528 题目大意:有一个很上的面板, 往上面贴海报, 问最后最多有多少个海报没有被完全覆盖 解题思路:将贴海报倒着想, 对于每一张海报只 ...
随机推荐
- 论文阅读:Fast, Scalable, and Programmable Packet Scheduler in Hardware
摘要: 随着链接速度的提高和CPU扩展速度的放缓,软件中的数据包调度会导致较低的精度和较高的CPU利用率. 通过将数据包调度卸载到诸如NIC之类的硬件,可以潜在地克服这些缺点.然而为了保持软件分组调度 ...
- [LOJ6433][PKUSC2018]最大前缀和:状压DP
分析 我们让每个数列在第一个取到最大前缀和的位置被统计到. 假设一个数列在\(pos\)处第一次取到最大前缀和,分析性质,有: 下标在\([1,pos]\)之间的数形成的数列的每个后缀和(不包括整个数 ...
- Oracle11g RAC+DG搭建
项目环境准备 3.1虚拟机配置 版本选择 注意Linux操作系统.此次项目我选择的版本是Oracle Enterprise Linux 5.4 内存的设置 本人电脑物理内存8G,由于此次实验要开三台虚 ...
- Spring之AOP配置
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- java期末课程总结
期末课程总结 转眼间,这个学期就要过去了,我们Java的学习也接近了尾声,回想到这个学期刚开始接触到Java的时候,感觉什么都不懂,但现在似乎有了门路,不会载懵懵懂懂, 虽然本学期面向对象与Java程 ...
- C语言转义字符表和ASCII码表
主要参考 http://www.51hei.com/mcu/4342.html 以及 https://www.cnblogs.com/jason207489550/p/6663444.html
- hud 5750 Dertouzos
Dertouzos Time Limit: 7000/3500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total ...
- 描述一下 Intent 和 IntentFilter?
Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内 ...
- jenkins docker 发布
分享下怎么使用jenkins 发布 docker 首先准备docker的相关部分 docker tomcat基础镜像,这边使用centos7做系统,dockerfile如下: #tomcat基础镜 ...
- select框动态添加选项
$.ajax({ url : "${staticServer }/ywgl/zkpzgl/zkfkgl/showBillType.htm", //ajax请求路径 type : & ...