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(线段树+区间操作)的更多相关文章

  1. POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化)

    POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化) 题意分析 贴海报,新的海报能覆盖在旧的海报上面,最后贴完了,求问能看见几张海报. 最多有10000张海报,海报 ...

  2. POJ 2528 Mayor's posters (线段树区间更新+离散化)

    题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值 ...

  3. poj 2528 Mayor's posters 线段树区间更新

    Mayor's posters Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=2528 Descript ...

  4. POJ 2528 Mayor's posters(线段树,区间覆盖,单点查询)

    Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 45703   Accepted: 13239 ...

  5. POJ 2528 Mayor's posters (线段树+区间覆盖+离散化)

    题意: 一共有n张海报, 按次序贴在墙上, 后贴的海报可以覆盖先贴的海报, 问一共有多少种海报出现过. 题解: 因为长度最大可以达到1e7, 但是最多只有2e4的区间个数,并且最后只是统计能看见的不同 ...

  6. poj 2528 Mayor's posters 线段树+离散化技巧

    poj 2528 Mayor's posters 题目链接: http://poj.org/problem?id=2528 思路: 线段树+离散化技巧(这里的离散化需要注意一下啊,题目数据弱看不出来) ...

  7. POJ 2528 Mayor's posters(线段树+离散化)

    Mayor's posters 转载自:http://blog.csdn.net/winddreams/article/details/38443761 [题目链接]Mayor's posters [ ...

  8. poj 2528 Mayor's posters 线段树+离散化 || hihocode #1079 离散化

    Mayor's posters Description The citizens of Bytetown, AB, could not stand that the candidates in the ...

  9. poj 2528 Mayor's posters(线段树)

    题目:http://poj.org/problem?id=2528 题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的, 但是必定是单位宽度的整数 ...

  10. POJ 2528 Mayor's posters (线段树)

    题目链接:http://poj.org/problem?id=2528 题目大意:有一个很上的面板, 往上面贴海报, 问最后最多有多少个海报没有被完全覆盖 解题思路:将贴海报倒着想, 对于每一张海报只 ...

随机推荐

  1. 计算机网络(三),TCP报文段详解

    目录 1.TCP(Transmission Control Protocol传输控制协议)作用 2.TCP报文段详解 三.TCP报文段详解 1.TCP(Transmission Control Pro ...

  2. 文献引用 .bib文件里有公式符号

    问题: 有时候文献标题带有特殊公式符号,进行BibTex编译时,会识别不出来公式符号. 例如: .bib文件里的文献: @article{XIE201892, title = "ℋ∞ con ...

  3. [BZOJ1001][BeiJing2006]狼抓兔子(最小割转最短路|平面图转对偶图)

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 31805  Solved: 8494[Submit][ ...

  4. C++入门经典-例6.12-使用数组地址将二维数组输出

    1:以a[4][3]为例 a代表二维数组的地址,通过指针运算符可以获取数组中的元素 (1)a+n代表第n行的首地址 (2)&a[0][0]既可以看作第0行0列的首地址,同样也可以被看作是二维数 ...

  5. 网络1911、1912 C语言第2次作业--循环结构 批改总结

    一.评分规则 伪代码务必是文字+代码描述,直接反应代码,每题扣1分 提交列表没内容,或者太简单,每题得分0分.注意选择提交列表长的题目介绍. 代码格式不规范,继续扣分. 代码互评,内容简单,0分. 原 ...

  6. Spark学习(一)——Spark运行架构

    基本概念 在具体讲解Spark运行架构之前,需要先了解几个重要的概念: RDD:是弹性分布式数据集(Resilient Distributed Dataset)的简称,是分布式内存的一个抽象概念,提供 ...

  7. PHP CI 框架初识(一)

    CodeIgniter 是一个简单快速的PHP MVC框架.EllisLab 的工作人员发布了 CodeIgniter.CodeIgniter 是一套小巧但功能强大的.给 PHP 网站开发者使用的 W ...

  8. ansible 剧本进阶 角色

    主要内容: playbook(剧本) roles 一.查看收集到的信息 ansible cache -m setup setup (需要了解的参数) ansible_all_ipv4_addresse ...

  9. 并查集练习(0743) SWUST OJ

    #include<iostream> #include<cstring> using namespace std; ]; int n,m,l,ci,di; int root(i ...

  10. git远程分支被误删,本地分支还存在,如何恢复远程分支?

    做项目的时候碰到了这样一件事:本地分支存在,远程分支不在了,如图: (git branch -a 是查看本地和远程分支,红色部分是远程分支) (git branch -r 是查看远程分支的) 奇怪的是 ...