poj_2528Mayor's posters(线段树)

标签: 线段树


题目连接

Mayor's posters

Time Limit: 1000MS Memory Limit: 65536K

Total Submissions: 57848 Accepted: 16730

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 li 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 <= li <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered li, li+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

Source

Alberta Collegiate Programming Contest 2003.10.18

  • 题意:选区有很多的竞选者,他们要在一面墙上贴大字报,后来的人可以覆盖前面的人贴的大字报,每次会给出大字报的其实位置和终止位置(注意,这里的编号是d对于每个单位线段,而不是对点,注意仔细看图)问最后一个人贴完大字报,墙面上一共可以看到几张大字报,注意,能看到一部分也算可以看到。

  • 题解:这个是线段树一个典型的应用,推荐一个很好地ppt,百度搜索浙江大学ppt线段树的讲解就很好。这里线段树中的一个域保存,当前节点的颜色值,这个题可以理解成给一面墙染不同的颜色。如果当前节点全部被同颜色覆盖,那么更新这个点的域为此颜色的编号。如果这个点没有染色,或者有多重颜色的话就更新这个点的域值为-1.

因为这个是我的打的第一个线段树,所以我来讲解一下初步理解的线段树的知识和用法


线段树是一个二叉查找树

线段树一般解决的问题是有关区间的动态修改和查询的问题。

首先要明确的是二叉查找树的性质,有点类似于二分查找的过程,可以仔细理解一下,下面说一下建立一棵树可以直接用数组来保存每个点,因为二叉树的性质,对于每个点来说,他的左孩子的编号是当前节点编号的二倍,表示为:\(rt<<2\),右孩子编号为其左孩子编号+1,表示为:\(rt<<1|1\)

那么在更新操作的时候有两种写法,两种理解,第二种不是很好理解,但是写法简单,且不容易出错。下面介绍一下这两种写法:

但是注意无论是哪种写法,建图的时候都是将中间节点归到左孩子。

A.需要截断区间

  1. 第一种理解是每次都将区间截取,考虑,如果所查询的区间刚好覆盖当前节点的话就将这个点的域(col[rt])直接更新;
  2. 取当前节点的中间点\(m = (l+r)>>1\)
  3. 如果要查询的区间的右端点\(R\)满足\(R<=m\) 则只用更新左孩子

    如果要查询的区间的左端点\(L\)满足\(L>m\) 则只用更新右孩子
  4. 如果上面都不满足,需要截取区间,更新左孩子,此时查找区间为\(L\)~\(m\)

    然后再跟新右孩子,此时的查找区间为\(m+1\)~\(R\)

其对应的代码如下

Update(int L, int R, int c, int l, int r, int rt)//L,R是要查询的区间,l,r是当前点的区间
{
if(L==l&&R==r){
col[rt] = c;
return;
}
int m = (l+r)>>1;
if(R<=m) Update(L,R,c,l,m,rt<<1);
else if(L>m) Update(L,R,c,m+1,r,rt<<1|1);
else {
Update(L,m,c,l,m,rt<<1);
Update(m+1,R,c,m+1,r,rt<<1|1);
}
}

B.不用截断区间

  1. 如果要询问的区间覆盖这个区间,即\(L<=l&&R>=r\)则对于这个点是一定要整个点更新的,所以直接更新并返回就可以了

  2. 取当前节点的中间点\(m = (l+r)>>1\)

  3. 如果当前要询问的点的右端点超过了中间节点的话即\(R>m\),说明右边的节点有需要更新的点,所以要将右孩子更新。

  4. 如果当前要询问的点的左端点超过了中间节点的话即\(L<=m\),说明左边的节点有需要更新的点,所以要将左孩子更新。

    这样代码比较简单,如下:

void Update(int L, int R, int l, int r, int c, int rt)
{
if( L <= l && R >= r )
{
col[rt] = c;
return;
}
if(col[rt]!=-1) PushDown(rt);
int m = (l+r)>>1;
if(L <= m ) Update(L,R,l,m,c,rt<<1);
if(R > m) Update(L,R,m+1,r,c,rt<<1|1);
}

查询的时候同样的方法有两种理解。

这里介绍线段树一种很重要的思想,就是懒操作的思想,就是在处理到某个节点的时候指示标记这个节点的状态,而不继续把影响下推下去,只有当用到这个点的时候或者需要下推的时候再将影响下推下去。

对于这个题的下推代码和查询代码主要的思想和核心弄懂了以后就不再赘述,直接上代码。一定要注意的是这个题的数据十分大,如果要想开的下这个数组,所以要先离散化一下。下面介绍一下什么是离散化。

  • 离散化:

    对于数字的离散化离散化可以想到,是将这些数字排序,对应的下标就是离散化结果,所以在找对应的下标的时候都要用到的是二分查找。但是这个题要注意一个问题,就是考虑110,14,6~10这三个大字报来说如果按照常规的离散化的思路来说的话,会出现问题,就是中间的空隙值没有离散化,为了避免这样的情况,我们每次讲这个点的右端点加1的值也加入这个数组,一起里散话,既可以避免这个问题了。

下面是这个题ac代码:



#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
#define M 10005
int m,li[M],ri[M];
int xx[M<<3];
int x[M<<3],col[M<<4],ans;
bool _hash[M];
void PushDown(int rt){//懒操作?
col[rt<<1] = col[rt<<1|1] = col[rt];
col[rt] = -1;
}
void Update(int L, int R, int c, int l, int r, int rt){
if(l>=L&&r<=R){ //L和R是要查询的区间,要查询的区间包含当前节点区间
col[rt] = c;
return;
}
if(col[rt]!=-1) PushDown(rt);
int m = (l+r)>>1;
if(m >= L) Update(L,R,c,l,m,rt<<1);//如果中点左边仍有要查询的点则要查询左结点
if(m < R) Update(L,R,c,m+1,r,rt<<1|1);//如果中间节点右边仍有要查询的点要搜索其右子树
//这里要注意的是大于和小于的区别,因为建图的时候是左边包含中间节点
}
void query(int l, int r, int rt){//查询不是很懂,这里它为什么要遍历整棵书呢?
if(~col[rt] || l == r){
if(~col[rt] && !_hash[col[rt]]){
ans++;
_hash[col[rt]] = true;//这个是干啥的?看上去这个像是对某种颜色是否出现过hash
}
return;
}
// if(col[rt] != -1) PushDown(rt);
int m = (l+r)>>1;
query(l,m,rt<<1);
query(m+1,r,rt<<1|1);
}
int BSearch(int ll,int hh,int xx){
int mm;
while(ll<=hh){
mm = (ll+hh)>>1;
if(x[mm]==xx) return mm;
else if(x[mm]>xx) hh = mm-1;
else ll = mm+1;
}
return -1;
}
int main()
{
int t,n,i;
scanf("%d",&t);
while(t--){
memset(col,-1,sizeof(col));
memset(_hash,0,sizeof(_hash));
int nn = 0;
scanf("%d",&n);
for(i = 1; i <= n; i++){
scanf("%d%d",&li[i],&ri[i]);
x[++nn] = li[i];
x[++nn] = ri[i];
x[++nn] = ri[i]+1; }
sort(x+1,x+nn+1);
m = unique(x+1, x+nn+1) - x - 1;
for(i = 1; i <= n; i++){
int l = BSearch(1,m,li[i]);
int r = BSearch(1,m,ri[i]);
//printf("(%d %d)\n", l, r);
Update(l,r,i,1,m,1);
}
ans = 0;
query(1,m,1);
//for(int i = 1; i <= m; i++)printf("%d ", _hash[i]);puts("");
printf("%d\n",ans);
}
return 0;
}
下面是我又敲了一遍的。。一起码上吧
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N = 10005;
#define dd puts("haha");
int li[N],ri[N];
int x[N<<3];
int col[N<<4];
bool Hash[N];
void PushDown(int rt){
col[rt<<1] = col[rt];
col[rt<<1|1] = col[rt];
col[rt] = -1;
return;
}
void Update(int L, int R, int l, int r, int c, int rt)
{
if( L <= l && R >= r ) {
col[rt] = c;
return;
}
if(col[rt]!=-1) PushDown(rt);
int m = (l+r)>>1;
if(L <= m ) Update(L,R,l,m,c,rt<<1);
if(R > m) Update(L,R,m+1,r,c,rt<<1|1);
}
int ans;
void query(int l, int r, int rt)
{
if(l==r||~col[rt]){//~col[rt]相当于col[rt]!=-1;因为~是按位取反的意思
if(!Hash[col[rt]]&&(col[rt]!=-1)){
ans++;
Hash[col[rt]] = 1;
}
return;
}
if(~col[rt])PushDown(rt);
int m = (l+r)>>1;
query(l,m,rt<<1);
query(m+1,r,rt<<1|1);
}
int BSearch(int l, int r, int c)
{
int m;
while(l<=r){
m =(l+r)>>1;
if(x[m]==c) return m;
else if(x[m]<c) l = m+1;
else if(x[m]>c) r = m-1;
}
return -1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(col,-1,sizeof(col));
memset(Hash,0,sizeof(Hash));
int n;
scanf("%d",&n);
int cnt = 1;
for(int i = 1; i <=n; i++)
{
scanf("%d %d",&li[i],&ri[i]);
x[cnt++] = li[i];
x[cnt++] = ri[i];
x[cnt++] = ri[i]+1;
}
sort(x+1,x+cnt+1);
int m = unique(x+1,x+cnt+1)-x-1;
for(int i = 1; i <= n; i++){
int ll = BSearch(1,m,li[i]);
int rr = BSearch(1,m,ri[i]);
//printf("(%d %d)\n",ll,rr);
Update(ll,rr,1,m,i,1);
}
//dd;
ans = 0;
query(1,m,1);
printf("%d\n",ans);
}
return 0;
}

poj_2528Mayor's posters(线段树)的更多相关文章

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

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

  2. POJ2528Mayor's posters[线段树 离散化]

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

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

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

  4. Mayor's posters(线段树+离散化POJ2528)

    Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 51175 Accepted: 14820 Des ...

  5. [poj2528] Mayor's posters (线段树+离散化)

    线段树 + 离散化 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayor ...

  6. poj-----(2528)Mayor's posters(线段树区间更新及区间统计+离散化)

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

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

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

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

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

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

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

随机推荐

  1. Java 伙伴系统(模拟)

    参考:https://labrick.cc/2015/10/12/buddy-system-algorithm/ 代码过烂 不宜参考. output: [operating.entity.Heap@4 ...

  2. 第五节 suid/ sgid /sbit /which /locate / find /stat / ln / uname -a

    复习上节课内容(重点记录)1.chown -R 递归修改目录下包含子目录和子目录下的文件的属组2.chmod -R 递归修改目录下包含子目录和子目录下的文件的权限 ================== ...

  3. NIO中的易筋经

    匠心零度 转载请注明原创出处,谢谢! 前言 <易筋经>.天下武功出少林,而易筋经是少林寺的镇寺之宝.学好了易筋经就可以轻易地学好其它武功,只不过很少人学到了它的全部精髓.游坦之只是碰巧学了 ...

  4. 配置linux下apache跨域问题

    1.apache设置允许远程访问 打开FTP,登录服务器,找到etc文件夹下的httpd.conf文件,然后下载到本地 打开本地httpd.conf文件夹,找到对应的端口ip地址,修改如下 <V ...

  5. jquery图片延迟加载 及 serializeArray、serialize用法记录

    1.使用jquery实现 图片延迟加载 由于用户访问页面需要加载很多的图片,延迟加载技术在电子商务网站领域越来越普及,淘宝商城,京东商城,凡客等访问量巨大的电子商务站点为了增加用户用户体验,访问速度以 ...

  6. Android基础夯实--你了解Handler有多少?

    概述 对于刚入门的同学来说,往往都会对Handler比较迷茫,到底Handler是个什么样的东西.当然,可能对于一些有工作经验的工程师来说,他们也不一定能很准确地描述,我们来看下API的介绍. Han ...

  7. PHP使用google api生成二维码

    代码如下: <?php $urlToEncode="nickname:Feanmy,email:feanmy@qq.com"; generateQRfromGoogle($u ...

  8. ORA-00600[17059]错误

    ORA-00600[17059] ORA-00600[17059]错误大部分都是因为高版本导致,对于本库的分析:因为该库的 shared pool老化比较频繁,到我介入的时候,发现相关该类此sql已经 ...

  9. (python)leetcode刷题笔记03 Longest Substring Without Repeating Characters

    3. Longest Substring Without Repeating Characters Given a string, find the length of the longest sub ...

  10. Java Web高级编程(二)

    使用会话维持状态 一.会话 为了实现关联同一个用户端的多个请求和这些请求之间数据的共享,需要用到会话,会话用于维持请求和请求之间的状态.从服务器的角度,当用户的Web浏览器打开第一个链接到服务器的套接 ...