第二次
/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
Copyright (c) 2011 panyanyany All rights reserved.
URL : http://poj.org/problem?id=2528
Name : 2528 Mayor's posters
Date : Saturday, October 1, 2011
Time Stage : one and half an hours
Result:
9378439 panyanyany
2528
Accepted 1248K 79MS C++
3804B 2011-10-01 00:36:01
9378423 panyanyany
2528
Wrong Answer C++
3707B 2011-10-01 00:30:47
Test Data :
Review :
第二次做,还是有很多地方没有注意到的。比如 2 * n,以及递归到达叶子时没有判断 和 退出
//----------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;
typedef __int64 LL ;
int max (int lhs, int rhs)
{
return (lhs > rhs ? lhs : rhs) ;
}
int min (int lhs, int rhs)
{
return lhs < rhs ? lhs : rhs ;
}
#define MAXSIZE 10010
#define L(n) ((n) << 1)
#define R(n) (((n) << 1) + 1)
#define MID(a, b) (((a) + (b)) >> 1)
// 此结构体用来映射新的端点值
typedef struct {
bool isLeft ; // 判断此端点是否左端点
int id ; // 标记此站点是第几个端点
int val ; // 此端点的原来的值
} MAP ;
// 此结构体用来做线段树的节点
typedef struct {
int id ; // 海报序号,若为0则表示在[left,right]内海报的张数不确定
int left, right ; // left , right 分别代表此区间的 左,右 端点
} NODE ;
int tcase, n, cnt ;
bool flag[MAXSIZE] ;
int left[MAXSIZE], right[MAXSIZE] ;
MAP map[MAXSIZE * 2] ;
NODE tree[MAXSIZE * 14] ;
int cmp(MAP lhs, MAP rhs)
{
return lhs.val < rhs.val ;
}
void build (int node, int left, int right)
{
tree[node].id = 0 ;
tree[node].left = left ;
tree[node].right = right ;
if (left == right)
return ;
int mid = MID (left, right) ;
build (L(node), left, mid) ;
build (R(node), mid + 1, right) ;
}
void update (int node, int left, int right, int NewId)
{
// 若张贴的海报刚好覆盖当前区间,则当前区间的 id 为该海报的 id
if (tree[node].left == left && tree[node].right == right ||
tree[node].left == tree[node].right)
{
tree[node].id = NewId ;
return ;
}
// 若海报不足以完全覆盖当前区间
// 若此区间之前已经被某海报完全覆盖
if (tree[node].id != 0)
{
tree[L(node)].id = tree[node].id ; // 假设左子树不被海报覆盖,则其 id 为根区间的 id
tree[R(node)].id = tree[node].id ; // 假设右子树不被海报覆盖,则其 id 为根区间的 id
tree[node].id = 0 ; // 因为在此区间内有两张海报,则此区间的 id 为不确定
}
int mid = MID (tree[node].left, tree[node].right) ;
// 若海报仅能覆盖左半区间
if (right <= mid)
update (L(node), left, right, NewId) ;
// 若海报仅能覆盖右半区间
else if (mid < left)
update (R(node), left, right, NewId) ;
// 若海报横跨本区间中部
else
{
update (L(node), left, mid, NewId) ;
update (R(node), mid + 1, right, NewId) ;
}
}
void count (int node)
{
// 若此区间恰有一张海报
if (tree[node].id)
{
// 若此海报未被记录
if (flag[tree[node].id] == false)
{
flag[tree[node].id] = true ;
++cnt ;
}
return ;
}
// 已经到达叶子,此节点仍为不确定状态,则退出
if (tree[node].left == tree[node].right)
return ;
// 若此区间的海报数量不确定
// 则递归查找子区间
count (L(node)) ;
count (R(node)) ;
}
int main ()
{
int i, j ;
int t, tmp ;
while (scanf ("%d", &tcase) != EOF)
{
while (tcase--)
{
scanf ("%d", &n) ;
for (i = 1 ; i <= n ; ++i)
{
scanf ("%d%d", &left[i], &right[i]) ;
map[i * 2 - 1].id = i ;
map[i * 2 - 1].isLeft = true ;
map[i * 2 - 1].val = left[i] ;
map[i * 2].id = i ;
map[i * 2].isLeft = false ;
map[i * 2].val = right[i] ;
}
// 把端点值按从小到大排序, 注意 2 * n
sort (map + 1, map + 1 + 2 * n, cmp) ;
// 离散化
tmp = map[1].val ; // tmp 用来判断是否与前一个原始端点值相同
t = 1 ; // t 作为新的端点值(离散化)
// 注意 2 * n
for (i = 1 ; i <= 2 * n ; ++i)
{
if (tmp != map[i].val)
{
tmp = map[i].val ;
++t ;
}
if (map[i].isLeft == true)
{
left[map[i].id] = t ;
}
else
{
right[map[i].id] = t ;
}
}
// 注意 2 * t
build (1, 1, 2 * t) ; // 构造线段树
// 更新线段树
for (i = 1 ; i <= n ; ++i)
update (1, left[i], right[i], i) ;
memset (flag, false, sizeof (flag)) ;
cnt = 0 ;
count (1) ;
printf ("%d\n", cnt) ;
}
}
return 0 ;
}
第一次
/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
Copyright (c) 2011 panyanyany All rights reserved.
URL : http://poj.org/problem?id=2528
Name : 2528 Mayor's posters
Date : Monday, September 26, 2011
Time Stage : Three hours
Result:
9363927 panyanyany
2528
Accepted 1252K 94MS C++
3304B 2011-09-26 21:12:59
9363885 panyanyany
2528
Accepted 1272K 94MS C++
3738B 2011-09-26 21:05:46
9363864 panyanyany
2528
Wrong Answer C++
3616B 2011-09-26 21:01:08
9363854 panyanyany
2528
Wrong Answer C++
3612B 2011-09-26 20:59:25
9363846 panyanyany
2528
Compile Error
C++
3544B 2011-09-26 20:58:31
9363671 panyanyany
2528
Time Limit Exceeded C++
3370B 2011-09-26 20:16:14
9363662 panyanyany
2528
Runtime Error C++
3369B 2011-09-26 20:15:02
9363631 panyanyany
2528
Runtime Error C++
3337B 2011-09-26 20:09:37
9363613 panyanyany
2528
Runtime Error C++
3341B 2011-09-26 20:06:49
9363610 panyanyany
2528
Runtime Error C++
3332B 2011-09-26 20:06:02
9363604 panyanyany
2528
Runtime Error C++
3332B 2011-09-26 20:05:09
Test Data :
Review :
首先感谢几位大牛的解题报告:
AC_Von,http://www.cnblogs.com/vongang/archive/2011/08/10/2133869.html
kuangbin,http://www.cnblogs.com/kuangbin/archive/2011/08/15/2139931.html
思路:
这题的思想,主要是离散化,当然还有一些小技巧。
离散化,大概就是:
由于不可能开1000,0000的数组,又注意到其实际有效数据才
10000 对,在最坏的情况下,将有 2000 个不同的数据。
比如:
n = 5 ;
1,200,3,5000,8999,100000, 999,9999999999
若直接以上面的数字作下标,则起码要开 9999999999 大小的数组,
显然是不可能的。
若将上面的数列排序,则:
1,3,200,999,5000,8999,100000,9999999999
根据排序的顺序,映射新的下标:
1,3,200,999,5000,8999,100000,9999999999
1,2,3, 4, 5, 6, 7, 8
则我们其实只开 8 大小的数组就可以了!
血泪史:
一开始数组开小了,无限RE,
后来用一个循环去遍历整棵树,TLE,
于是将 count() 函数的查找改为递归模式,同时修改 update() 函数,正式确定
Tree[node].sum 的作用,当为 0 时,表示当前区间的海报数量不确定,
当为正整数值时,表示当前区间只有某海报
后来VC6或者VA的复制发了神经,后面截断一大片,又CE,
重新复制后,WA,
最后一次改错,是标记重复
//----------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;
typedef __int64 LL ;
int max (int lhs, int rhs)
{
return (lhs > rhs ? lhs : rhs) ;
}
int min (int lhs, int rhs)
{
return lhs < rhs ? lhs : rhs ;
}
#define MAXSIZE 10010
#define L(n) ((n) << 1)
#define R(n) (((n) << 1) + 1)
typedef struct {
int id ;
int endVal ;
bool isLeft ;
} TAG ;
typedef struct {
int id ;
int left, right ;
} NODE ;
bool flag[MAXSIZE * 2] ;
int tcase, n, cnt ;
int num[MAXSIZE][2] ;
TAG tag[MAXSIZE * 2] ;
NODE tree[10 * (MAXSIZE)] ;
int cmp (TAG ta, TAG tb)
{
return ta.endVal < tb.endVal ;
}
void build (int node, int left, int right)
{
tree[node].left = left ;
tree[node].right = right ;
// 0 表示当前区间的海报数量不确定,正整数则表示当前区间完全被某海报覆盖
tree[node].id = 0 ;
if (tree[node].left == tree[node].right)
return ;
int mid = (left + right) / 2 ;
build (L(node), left, mid) ;
build (R(node), mid + 1, right) ;
}
void update (int node, int left, int right, int id)
{
// 若新的海报可以覆盖当前区间
if (left <= tree[node].left && tree[node].right <= right)
{
tree[node].id = id ;
return ;
}
/*
// [left, right] 与 node 所在区间无交集
if (tree[node].right < left || right < tree[node].left)
return ;
*/
// 若当前区间已经被海报覆盖过,且新的海报只能覆盖部分区间
if (tree[node].id > 0)
{
tree[L(node)].id = tree[node].id ;
tree[R(node)].id = tree[node].id ;
// 重新将此区间的海报数量置于不确定状态
tree[node].id = 0 ;
}
// [left, right] 与 node 所在区间有交集
int mid = (tree[node].left + tree[node].right) / 2 ;
// [left, right] 在 node 左半区间
if (right <= mid)
update (L(node), left, right, id) ;
// [left, right] 在 node 右半区间
else if (mid < left)
update (R(node), left, right, id) ;
// [left, right] 在 node 两半都有, 即在 node 中部
else
{
update (L(node), left, mid, id) ;
update (R(node), mid + 1, right, id) ;
}
return ;
}
void count (int node)
{
// 表示此区间只有一张编号为 id 的海报
if (tree[node].id > 0)
{
// 此海报是否已经计算过
if (flag[tree[node].id] == false)
{
++cnt ;
flag[tree[node].id] = true ;
}
return ;
}
// 已经到达叶子,此节点仍为不确定状态,则退出
if (tree[node].left == tree[node].right)
return ;
// 对于不确定的树,向左右两边搜索
count (L(node)) ;
count (R(node)) ;
}
int main ()
{
int i, j ;
while (scanf ("%d", &tcase) != EOF)
{
while (tcase--)
{
memset (flag, 0, sizeof (flag)) ;
scanf ("%d", &n) ;
for (i = 1 ; i <= n ; ++i)
{
scanf ("%d%d", &num[i][0], &num[i][1]) ;
tag[2 * i - 1].id = i ;
tag[2 * i - 1].isLeft = true ;
tag[2 * i - 1].endVal = num[i][0] ;
tag[2 * i].id = i ;
tag[2 * i].isLeft = false ;
tag[2 * i].endVal = num[i][1] ;
}
sort (tag + 1, tag + 2 * n + 1, cmp) ;
int t = 1, tmp = tag[1].endVal ;
for (i = 1 ; i <= 2 * n ; ++i)
{
// 本来以为这一句不加也没关系,结果WA了,跳过重复的值,
if (tmp != tag[i].endVal)
{
tmp = tag[i].endVal ;
++t ;
}
if (tag[i].isLeft == true)
num[tag[i].id][0] = t ;
else
num[tag[i].id][1] = t ;
}
build (1, 1, 2 * n) ;
for (i = 1 ; i <= n ; ++i)
{
update (1, num[i][0], num[i][1], i) ;
}
cnt = 0 ;
count (1) ;
printf ("%d\n", cnt) ;
}
}
return 0 ;
}
分享到:
相关推荐
POJ2528-Mayor's posters 【区间映射压缩(离散化)+线段树】 解题报告+AC代码 http://hi.csdn.net/!s/83XZJU ========> 我的所有POJ解题报告链接: http://blog.csdn.net/lyy289065406/article/details/6642573
【标题】"poj-2528 Mayor's posters 测试数据及答案"涉及的是一个编程竞赛中的问题,这个问题来源于POJ(Programming Online Judge)平台,编号为2528。POJ是一个在线的编程练习系统,它提供了一系列的问题供程序员...
【标题】"POJ2528-Mayor's posters"是一个经典的编程竞赛题目,源自2003年Alberta Collegiate Programming Contest。该比赛每年都会吸引众多编程爱好者参加,旨在锻炼参赛者的算法设计和实现能力。题目“市长的海报...
线段树是一种数据结构,常用于处理区间查询与更新的问题,它能高效地支持动态维护区间最值、求和等问题。在本题“POJ 3264”中,我们可能面临的是一个区间最值或者区间求和的计算任务。线段树的基本思想是将数组或...
在本教程中,我们将深入探讨线段树的基本概念,以及如何使用Java实现线段树来解决实际问题,如POJ3468题目。 首先,理解线段树的核心在于它的分治思想。线段树将一个大区间(通常是一维数组)分成多个小区间,每个...
标题中的“POJ3277.rar_3277 poj_poj3277_多个面积_线段树”是指一个与编程竞赛相关的压缩文件,特别提到了POJ(Problemset Online Judge)的第3277号问题。POJ是一个著名的在线编程竞赛平台,参与者需要解决各种...
在本篇博文中,我们将深入探讨线段树的概念,以及如何实现懒惰更新(Lazy Propagation)策略,同时结合POJ1823问题进行实战应用。懒惰更新是优化线段树性能的关键技巧,它避免了频繁地对每个节点进行更新,从而减少...
### POJ 2352 Stars - 树状数组与线段树实现 #### 题目背景 POJ 2352 Stars 是一道经典的算法题目,它提供了使用树状数组或线段树来解决的可能性。这两种数据结构都是为了高效处理区间查询问题而设计的。在这篇...
【标题】"POJ1159-Palindrome" 是北京大学在线编程平台POJ上的一道编程题目。这道题目主要考察的是字符串处理和回文判断的知识点。 【描述】"北大POJ1159-Palindrome 解题报告+AC代码" 暗示了解决这道问题的方法和...
在`poj2823.cpp`源代码中,我们可以看到实现线段树的具体细节,包括如何初始化、更新以及查询线段树。此外,代码可能还包括了问题的输入输出处理,错误检查,以及可能的优化策略,比如lazy propagation(惰性传播)...
很多的POJ题目答案!1000~1008,1011~1014,1016,1017,1019,1028,1032,1045,1046,1047,1050,1061,1067,1068,1088,1102,1159,1163,1183,1207,1218,1226,1247,1256,1258,1298,1316,1323,...
《北大ACM题解》是一本专为解决POJ(Programming Online Judge)平台上的编程竞赛题目而编写的指导书籍。ACM(国际大学生程序设计竞赛,International Collegiate Programming Contest)是一项全球性的比赛,旨在...
《北大POJ经典结题报告》是一份针对北京大学在线编程平台POJ的解题报告,旨在帮助学习者掌握算法和编程技巧,提升解决问题的能力。POJ(Problem Online Judge)是北大的一个在线编程竞赛系统,提供了丰富的算法题目...
- **POJ 2528**:这是一道稍微复杂一点的线段覆盖问题,需要使用离散化技术。题目中的输入数据范围可能很大,直接存储会消耗大量的内存空间。因此,首先需要对所有涉及的点进行离散化处理,压缩点的范围,减少所需的...
【标题】"北大POJ大量解题代码"指的是北京大学在线编程平台POJ上的一系列算法题目解决方案的集合。这些代码通常由ACM(国际大学生程序设计竞赛)参赛者或爱好者编写,旨在帮助学习者理解并解决各类算法问题,提高...
北京大学在线编程平台POJ(PKU Online Judge)是许多学习算法和进行编程训练的学生们的重要实践场所。这个“北大poj解题报告”包含了作者在使用POJ平台解题过程中的学习总结和经验分享,旨在帮助软件工程专业的学生...
### 线段树例题解析 #### Brackets (SPOJ61, BRCKTS) **题目描述:** 此题要求我们维护一个长度为 \(N\) 的小括号序列 \(A\),并支持两种操作: 1. **Replace(i)**:将第 \(i\) 个位置的括号方向反转。 2. **Check...
北京大学POJ题目类型分类 北京大学POJ题目类型分类是根据题目的难易程度、知识领域和解决方法对POJ题目进行分类的。通过对POJ题目的分类,可以帮助学习者更好地理解和掌握算法和数据结构的知识。 简单题 简单题是...
+ poj2528, poj2828, poj2777, poj2886, poj2750 * 静态二叉检索树 + poj2482, poj2352 * 树状树组 + poj1195, poj3321 * RMQ + poj3264, poj3368 * 并查集的高级应用 + poj1703, poj2492 * KMP算法 + poj1961...
10. **POJ 2528 线段树.txt**:这是第三个线段树相关的题目,解题报告可能会深入讲解线段树在不同场景下的应用。 通过阅读这些解题报告,你可以学习到各种高级算法的应用,如动态规划、搜索算法、数据结构(如线段...