hdu4831 Scenic Popularity(线段树)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4831
题目大概意思就是有多个风景区和休息区,每个风景区有热度,休息区的热度与最接近的分景区的热度相同,题目要求求出小于等于给定热度值的风景区和休息区的个数。显然如果直接暴力的话,复杂度为O(TKN),达到10^9次方数量级,复杂度过高,对于这种问答的题目,最一般的思路其实是线段树,线段树更改和查询的时间复杂度均为O(logn),所以如果用线段树的话,这道题目的复杂度为O(TKlogH),达到10^5左右的数量级,这个复杂度可以满足题目要求。
线段树的实现一般用完全二叉树来实现,每个节点都可以看做是一段"线段"或者某个”范围“(x,y],这道题目节点表示的”范围“就是某段景区热度值(x,y],同时节点还记录了在该”范围“中包含的景区和休息区的个数,所以树的叶子节点就是等于某个热度值的景区和休息区的个数。线段树的定义如下:
#define MAX_SIZE 100000
typedef struct _tree
{
int count;
int left, right;
}TreeNode;
TreeNode tree[ * MAX_SIZE + ];
void Init(int x, int left, int right)
{
tree[x].count = ;
tree[x].left = left;
tree[x].right = right;
if (left + == right)
return;
Init(x << , left, (left + right) >> );
Init((x << ) + , (left + right) >> , right);
}
void Update(int x, int coord, int count)
{
int left = tree[x].left;
int right = tree[x].right;
int mid = (left + right) >> ;
if (left + == right)
{
tree[x].count += count;
return;
}
if (coord <= mid)
Update(x << , coord, count);
else
Update((x << ) + , coord, count);
tree[x].count += count;
}
int Query(int x, int coord)
{
int left = tree[x].left;
int right = tree[x].right;
int mid = (left + right) >> ;
if (left + == right)
return tree[x].count;
if (coord <= mid)
return Query(x << , coord);
else if (coord > mid)
return tree[x << ].count + Query((x << ) + , coord);
}
每次更新某个景区的热度值时,受影响的是该景区和离该景区近的休息区的热度值,其它的景区和热度值是保持不变的,只要预处理离每个景区近的休息区的个数,就可以在更新某个景区的热度值后立马得到哪些景区和休息区的热度值受到影响,从而更新线段树。不过需要注意的是某个休息区同时与两个景区距离相同的情况。我的方法是对每个景区和休息区设置两个变量li和ri,如果是景区,li表示向前所能影响的最前的休息区,ri表示向后所能影响的最后的休息区;如果是休息区,并且有两个风景区到该休息区的距离相等,li和ri分别表示这两个风景区。有个这两个变量,对于给定的风景区,就能直接计算该风景区所影响的休息区个数。
typedef struct _xh
{
int x;
int h;
int li, ri;
}XH;
XH data[]; int GetCount(int x)
{
int cnt = data[x].ri - data[x].li + ;
if (data[x].li < x && data[data[x].li].li != - && data[data[data[x].li].li].h >= data[x].h)
cnt--;
if (data[x].ri > x && data[data[x].ri].ri != - && data[data[data[x].ri].ri].h > data[x].h)
cnt--;
return cnt;
}
有了上面的分析,对于给定的热度值获取小于等于这个热度值的景区和休息区的个数就简单了,直接查询线段树就可以了。
具体代码如下:
#include <stdio.h>
#include <string.h> #define MAX_SIZE 100000
typedef struct _tree
{
int count;
int left, right;
}TreeNode;
TreeNode tree[ * MAX_SIZE + ];
typedef struct _xh
{
int x;
int h;
int li, ri;
}XH;
XH data[]; typedef struct _qy
{
char op;
int x, h;
}QY;
QY qy[]; void Init(int x, int left, int right)
{
tree[x].count = ;
tree[x].left = left;
tree[x].right = right;
if (left + == right)
return;
Init(x << , left, (left + right) >> );
Init((x << ) + , (left + right) >> , right);
}
void Update(int x, int coord, int count)
{
int left = tree[x].left;
int right = tree[x].right;
int mid = (left + right) >> ;
if (left + == right)
{
tree[x].count += count;
return;
}
if (coord <= mid)
Update(x << , coord, count);
else
Update((x << ) + , coord, count);
tree[x].count += count;
}
int Query(int x, int coord)
{
int left = tree[x].left;
int right = tree[x].right;
int mid = (left + right) >> ;
if (left + == right)
return tree[x].count;
if (coord <= mid)
return Query(x << , coord);
else if (coord > mid)
return tree[x << ].count + Query((x << ) + , coord);
}
int GetCount(int x)
{
int cnt = data[x].ri - data[x].li + ;
if (data[x].li < x && data[data[x].li].li != - && data[data[data[x].li].li].h >= data[x].h)
cnt--;
if (data[x].ri > x && data[data[x].ri].ri != - && data[data[data[x].ri].ri].h > data[x].h)
cnt--;
return cnt;
}
int main(void)
{
int t, n, k, i, j, pl, pr, cnt, max, x, h, cntpre, cntnext, cntnew, cntnpre, cntnnext;
char op; scanf("%d", &t);
for (i = ; i < t; i++)
{
max = ;
memset(data, -, sizeof(data));
scanf("%d", &n);
for (j = ; j < n; j++)
{
scanf("%d%d", &data[j].x, &data[j].h);
if (max < data[j].h)
max = data[j].h;
}
scanf("%d", &k);
for (j = ; j < k; j++)
{
scanf("%1s", &qy[j].op);
if (qy[j].op == 'Q')
scanf("%d", &qy[j].h);
else
scanf("%d%d", &qy[j].x, &qy[j].h);
if (max < qy[j].h)
max = qy[j].h;
}
pl = pr = ;
while (pl < n && !data[pl].h)
pl++;
data[pl].li = ;
pr = pl + ;
while (pl < n)
{
while (pr < n && !data[pr].h)
pr++;
if (pr == n)
break;
if (pl + == pr)
{
data[pl].ri = pl;
data[pr].li = pr;
}
else
{
j = pl + ;
while (j < pr)
if (data[j]. x - data[pl].x < data[pr].x - data[j].x)
{
data[pl].ri = j;
data[pr].li = j + ;
j++;
}
else if (data[j]. x - data[pl].x == data[pr].x - data[j].x)
{
data[pl].ri = data[pr].li = j;
data[j].li = pl;
data[j].ri = pr;
break;
}
else
{
data[pr].li = j;
data[pl].ri = j - ;
break;
}
}
pl = pr++;
}
if (pl < n)
data[pl].ri = n - ;
Init(, , max);
for (j = ; j < n; j++)
if (data[j].h)
{
cnt = GetCount(j);
Update(, data[j].h, cnt);
}
printf("Case #%d:\n", i + );
for (j = ; j < k; j++)
if (qy[j].op == 'Q')
printf("%d\n", Query(, qy[j].h));
else
{
x = qy[j].x;
h = qy[j].h;
cnt = GetCount(x);
Update(, data[x].h, -cnt);
cntpre = cntnext = cntnpre = cntnnext = ;
if (data[x].li < x && data[data[x].li].li != -)
cntpre = GetCount(data[data[x].li].li);
if (data[x].ri > x && data[data[x].ri].ri != -)
cntnext = GetCount(data[data[x].ri].ri);
data[x].h = h;
cntnew = GetCount(x);
Update(, data[x].h, cntnew);
if (data[x].li < x && data[data[x].li].li != -)
cntnpre = GetCount(data[data[x].li].li);
if (data[x].ri > x && data[data[x].ri].ri != -)
cntnnext = GetCount(data[data[x].ri].ri);
if (cntpre != cntnpre)
Update(, data[data[data[x].li].li].h, cntnpre - cntpre);
if (cntnext != cntnnext)
Update(, data[data[data[x].ri].ri].h, cntnnext - cntnext);
}
}
return ;
}
hdu4831 Scenic Popularity(线段树)的更多相关文章
- HDU 4831 Scenic Popularity (段树)
Scenic Popularity Problem Description 临近节日,度度熊们近期计划到室外游玩公园.公园内部包含了非常多的旅游景点区和歇息区,因为旅游景点非常热门,导致景点区和歇息区 ...
- HDU 4831 Scenic Popularity
Scenic Popularity Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- CodeForces - 150C :Smart Cheater (线段树,求最大连续区间)
I guess there's not much point in reminding you that Nvodsk winters aren't exactly hot. That increas ...
- bzoj3932--可持久化线段树
题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...
- codevs 1082 线段树练习 3(区间维护)
codevs 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...
- codevs 1576 最长上升子序列的线段树优化
题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...
- codevs 1080 线段树点修改
先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...
- codevs 1082 线段树区间求和
codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...
- PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树
#44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...
随机推荐
- Cocopod
装了好几天,这个是比较全面的,大家可以看看帮助一下 1.新建一个项目,名称:CPTest 2.打开终端,输入"cd"+空格,然后将文件夹拖入到后面 3.回车后继续输入vim Pod ...
- Java 用程序给出随便大小的10 个数,序号为1-10,按从小到大顺序输出,并输出相应的序号?
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.uti ...
- 移动端图片上传base64编码
$base64 = "/9j/4AAQSkZJRgABAQEAkACQAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAA ...
- ps 实例部分
实例篇1:将不同图片通过阀值转换成黑白色人物头像 图像-黑白-曲向-阀值 本图像-复制-粘贴
- Collections+Iterator 接口 | Map+HashMap+HashTable+TreeMap |
Collections+Iterator 接口 1. Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询 ...
- Java NIO3:通道和文件通道
通道是什么 通道式(Channel)是java.nio的第二个主要创新.通道既不是一个扩展也不是一项增强,而是全新的.极好的Java I/O示例,提供与I/O服务的直接连接.Channel用于在字节缓 ...
- MySQL5.7 新增配置
1.log_timestamps 在5.7.2以后的版本中增加一个单独控制error log , general log,slow log的记录的时间,默认是UTC,需要配置成SYSTEM(本地时间) ...
- 干掉Unity3D
我为什么想干掉Unity3D? 这个问题容我不答,每个做技术的人总有一些完美主义. 你使用u3d的过程中是不是痛并快乐着呢. 就从两个国内具有相当普遍性的痛点说起. il2cpp,unity作出了这个 ...
- Azure PowerShell (12) 通过Azure PowerShell创建SSH登录的Linux VM
<Windows Azure Platform 系列文章目录> 本章将介绍如何使用Azure PowerShell,创建SSH登录的Linux VM 前提要求: 1.安装Azure Pow ...
- 用JavaScript调用WCF Service
原创地址:http://www.cnblogs.com/jfzhu/p/4039604.html 转载请注明出处 前面介绍过<Step by Step 创建一个WCF Service>和& ...