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 题目大意:有一个很上的面板, 往上面贴海报, 问最后最多有多少个海报没有被完全覆盖 解题思路:将贴海报倒着想, 对于每一张海报只 ...
随机推荐
- jquery focus()方法 语法
jquery focus()方法 语法 作用:当元素获得焦点时,发生 focus 事件.大理石平台价格 触发focus事件语法:$(selector).focus() 将函数绑定到focus事件语法: ...
- .netcore 图片处理
.netcore 图片处理 /// <summary> /// 根据文件类型和文件名返回新路径 /// </summary> /// <param name=" ...
- 使用word2vec对中文维基百科数据进行处理
一.下载中文维基百科数据https://dumps.wikimedia.org/zhwiki/并使用gensim中的wikicorpus解析提取xml中的内容 二.利用opencc繁体转简体 三.利用 ...
- STS插件_ springsource-tool-suite插件各个历史版本
目前spring官网(http://spring.io/tools/sts/all)上可下载的spring插件只有:springsource-tool-suite-3.8.4(sts-3.8.4).但 ...
- SpringBoot导入导出Excel到Mysql
2018.11.11 10:44:52字数 96阅读 1320 一.包的引用 除了引用SpringBoot基本包之外,还需要引入对Excel操作的包,如下: <dependency> &l ...
- nginx负载均衡 理解与测试
Nginx负载均衡概述 Web服务器,直接面向用户,往往要承载大量并发请求,单台服务器难以负荷,我使用多台WEB服务器组成集群,前端使用Nginx负载均衡,将请求分散的打到我们的后端服务器集群中,实现 ...
- C++入门经典-例6.18-数组的动态分配,动态获得斐波那契数列
1:有时在获得一定的信息之前,我们并不确定数组的大小.动态分配数组则可以使用变量作为数组的大小,使数组的大小符合我们的要求. 2:科普一下斐波纳契数列:斐波那契数列指的是这样一个数列 1, 1, 2, ...
- CentOS 6.4 搭建 ntop 网络流量监控分析平台
[前言] Ntop是一种监控网络流量工具,用ntop显示网络的使用情况比其他一些网络管理软件更加直观.详细.Ntop甚至可以列出每个节点计算机的网络带宽利用率. 功能: 自动从网络中识别有用的信息: ...
- Electron对JQuery的支持问题
最近在了解Electron框架写应用,偶然发现在html中使用<script src="./jquery.js"></script>这种方式引入JQuery ...
- HTML基础汇总
一.HTML的概述(了解) a.html是什么 : hypertext markup language 超文本标记语言 超文本:音频,视频,图片称为超文本.. ...