题目地址: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(线段树)的更多相关文章

  1. HDU 4831 Scenic Popularity (段树)

    Scenic Popularity Problem Description 临近节日,度度熊们近期计划到室外游玩公园.公园内部包含了非常多的旅游景点区和歇息区,因为旅游景点非常热门,导致景点区和歇息区 ...

  2. HDU 4831 Scenic Popularity

    Scenic Popularity Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  3. CodeForces - 150C :Smart Cheater (线段树,求最大连续区间)

    I guess there's not much point in reminding you that Nvodsk winters aren't exactly hot. That increas ...

  4. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  5. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  6. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  7. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  8. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  9. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

随机推荐

  1. Java的四种引用方式

    一.引用基本概念 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用.虚引用. 1.强引用(StrongRef ...

  2. python 函数之装饰器,迭代器,生成器

    装饰器 了解一点:写代码要遵循开发封闭原则,虽然这个原则是面向对象开发,但也适用于函数式编程,简单的来说,就是已经实现的功能代码不允许被修改但 可以被扩展即: 封闭:已实现功能的代码块 开发:对扩张开 ...

  3. 使用Python中PIL图形库进行截屏

    目的:通过使用Python的一个图形库PIL(Python Image Library)对屏幕进行截图 步骤: 1.下载PIL(路径)并安装 2.新建文件“截屏.py”,右键Edit with IDL ...

  4. Oracle CDC配置案例

    异步部署 1. 环境的配置准备 1.1.    数据库版本 SQL> select * from v$version; BANNER ------------------------------ ...

  5. ant的安装及项目的发布

    1.安装ant1) 直接解压apache-ant-1.9.7-bin 2) 在环境变量中配置,ant_home的环境变量在 3) 在命令提示符中测试是否安装成功. 2 项目首次打包1) 写好打包的配置 ...

  6. Hbuilder开发HTML5 APP之打开新页面

    mui.openWindow({ url: 'examples/info.html', id:'info' }); 要在页面间传递参数,需要使用一个extras:{}对象另外打开的页面显示的内容必须装 ...

  7. PostgreSQL 杂志

    pgmag 团队刚发布了头两期 PostgreSQL 杂志,还有中文版http://pgmag.org/download,推荐广大 PostgreSQL 数据库管理员及开发者阅读: Issue #01 ...

  8. A*寻路算法

    对于初学者而言,A*寻路已经是个比较复杂的算法了,为了便于理解,本文降低了A*算法的难度,规定只能横竖(四方向)寻路,而无法直接走对角线,使得整个算法更好理解. 简而言之,A*寻路就是计算从起点经过该 ...

  9. HaProxy+Keepalived+Mycat高可用群集配置

    概述 本章节主要介绍配置HaProxy+Keepalived高可用群集,Mycat的配置就不在这里做介绍,可以参考我前面写的几篇关于Mycat的文章. 部署图: 配置  HaProxy安装 181和1 ...

  10. 在.NET中使用管道将输出流转换为输入流

    最近在写一段代码,将本地文件压缩加密后发送到服务器,发送到服务器的类用一个输入流作为参数获取要上传的数据,而压缩类和加密类都是输出流. 如何将输出流转换为输入流,最直观的方法是缓存输出流的全部内容到内 ...