题目地址: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. webScoket的浅短的认识

    在一般的发送数据请求的时候都是用的http协议,但是对于类似即时聊天,需要客户端与服务器不间断的交互的时候对于http协议来说就不太适用了.因为http协议无法主动把数据发到客户端,而且客户端发送请求 ...

  2. mysql多字段排序

    在对数据库进行查询的时候有时候需要将查询的结果按照某字段升序或者降序排列,甚至有时候需要按照某两个字段进行升降序排列.如果按照某一字段进行排列,只需要在查询语句最后写上 "order by ...

  3. PMP备考_第六章_项目时间管理

    项目时间管理 前言 项目时间管理是项目管理中最难的一个环节,与个人时间管理类似,团体的效率如果管理不当,是低于个人效率的,为了管理好时间,从预估,执行到反馈均需要严格的分析和处理.如果制定的计划是无法 ...

  4. SQl SGA 整理

    --查看诊断位置信息 select * from v$diag_info; --查看sga中内存分配信息 select * from sys.x$ksmfs; --查看内存块还剩余多少 select ...

  5. 浅谈数据库优化方案--表和SQL

    1.数据类型的选择 1.字段最好设置为非空.若字段为char(8),即便是NULL也会现有8个字符的空间. 2.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能, ...

  6. maven报错非法字符:\65279 错误

    开发中一个项目很早就报这个错,maven报错非法字符:\65279 错误,今天终于忍无可忍要解决它 :编译java文件的时候,有些java文件报非法字符 \65279错误,在网上找和很多 方法,也试了 ...

  7. jquery 无刷新多级联动

    原先不熟悉jquery时,总在寻找无刷新的方法,在此不断的积累自己所知道的jquery属性,常用方法.以下为jquery实现的无刷新联动事件 分公司: <select id="Sele ...

  8. ubuntu 安装与开始学习

    下载地址 http://cn.ubuntu.com/download/ 经验: 1.遇到安装问题,首先尝试解读错误,再使用  ./configure --help  不行再上Stack overflo ...

  9. SharePoint 2010 Survey的Export to Spreadsheet功能怎么不见了?

    背景信息: 最近用户报了一个问题,说他创建的Survey里将结果导出成Excel文件(Export to spreadsheet)的按钮不见了. 原因排查: 正常情况下,这个功能只存在于SharePo ...

  10. Azure 新的管理模式 —— Resource Manager

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...