poj_2528Mayor's posters(线段树)
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.需要截断区间
- 第一种理解是每次都将区间截取,考虑,如果所查询的区间刚好覆盖当前节点的话就将这个点的域(col[rt])直接更新;
- 取当前节点的中间点\(m = (l+r)>>1\)
- 如果要查询的区间的右端点\(R\)满足\(R<=m\) 则只用更新左孩子
如果要查询的区间的左端点\(L\)满足\(L>m\) 则只用更新右孩子 - 如果上面都不满足,需要截取区间,更新左孩子,此时查找区间为\(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.不用截断区间
如果要询问的区间覆盖这个区间,即\(L<=l&&R>=r\)则对于这个点是一定要整个点更新的,所以直接更新并返回就可以了
取当前节点的中间点\(m = (l+r)>>1\)
如果当前要询问的点的右端点超过了中间节点的话即\(R>m\),说明右边的节点有需要更新的点,所以要将右孩子更新。
如果当前要询问的点的左端点超过了中间节点的话即\(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(线段树)的更多相关文章
- POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化)
POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化) 题意分析 贴海报,新的海报能覆盖在旧的海报上面,最后贴完了,求问能看见几张海报. 最多有10000张海报,海报 ...
- POJ2528Mayor's posters[线段树 离散化]
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 59683 Accepted: 17296 ...
- POJ 2528 Mayor's posters(线段树+离散化)
Mayor's posters 转载自:http://blog.csdn.net/winddreams/article/details/38443761 [题目链接]Mayor's posters [ ...
- Mayor's posters(线段树+离散化POJ2528)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 51175 Accepted: 14820 Des ...
- [poj2528] Mayor's posters (线段树+离散化)
线段树 + 离散化 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayor ...
- poj-----(2528)Mayor's posters(线段树区间更新及区间统计+离散化)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 43507 Accepted: 12693 ...
- poj 2528 Mayor's posters 线段树+离散化技巧
poj 2528 Mayor's posters 题目链接: http://poj.org/problem?id=2528 思路: 线段树+离散化技巧(这里的离散化需要注意一下啊,题目数据弱看不出来) ...
- POJ 2528 Mayor's posters (线段树+离散化)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions:75394 Accepted: 21747 ...
- poj 2528 Mayor's posters 线段树区间更新
Mayor's posters Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=2528 Descript ...
随机推荐
- iOS知识点、面试题 之二
最近面试,与大家分享一下,分三文给大家: 当然Xcode新版本区别,以及iOS新特性 Xcode8 和iOS 10 在之前文章有发过,感兴趣的可以查阅: http://www.cnblogs.com/ ...
- JavaScript的setter与getter方法
作者:http://hawkzz.com 以前在写项目过程一直都没有使用过Javascript的setter与getter方法,所以对其是一种要懂不懂的概念:今天看书看到这个知识点,还是模模糊糊的,于 ...
- 解决报错:IncompleteElementException: Could not find result map...
今天遇到这样一个报错,记录一下: org.apache.ibatis.builder.IncompleteElementException: Could not find result map com ...
- 外卖app的header组件开发
1.webpack框架创建 # 全局安装 vue-cli $ npm install --global vue-cli # 创建一个基于 webpack 模板的新项目 $ vue init webpa ...
- pstree 命令详解
作用: 以命令树状图的方式展现进程之间的派生关系, 显示效果比较直观. 选项: -a 显示每个程序的完整指令, 包含路径, 参数或者是常驻服务的标志 -c 不使用精简标示法 -h 列出树状图,特别标明 ...
- 从一个word文件中读取所有的表格和标题(2)
上一篇文章主要讲了从word底层xml中获取表格和标题的方法,但是存在一个问题:word文件必须是docx格式的.如果为doc格式的,可以有两种解决方案: 一.把doc文件转换成docx格式文件,用上 ...
- 从源码(编译)安装golang
从源码安装golang 通常情况下,安装go只需要在官网(https://golang.org/dl/)下载适合系统的二进制发布包,按照安装说明进行安装即可. 对于Linux, Mac OS X和Fr ...
- Appsacn 定期自动化扫描
appscan提供了计划扫描的选项,配合windows的计划任务,可以按需设定. 操作流程如下: 1.打开Appsacn--工具---扫描调度程序---新建 2.新建后显示如下窗口 3.填写好相应的设 ...
- csv文件转json
http://stackoverflow.com/questions/19766266/directly-convert-csv-file-to-json-file-using-the-jackson ...
- 怎么为WebStorm更换主题 修改字体样式
这篇文章主要用于帮助大家解决怎么为webstorm换theme. 首先,到选择一个自己喜欢的皮肤,Webstorm皮肤网址: http://phpstorm-themes.com/ 然后,选中你喜欢的 ...