题目地址: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. [LintCode] Trailing Zeroes 末尾零的个数

    Write an algorithm which computes the number of trailing zeros in n factorial. Have you met this que ...

  2. LabVIEW 吸星大法 - 看见的好东西都是我的(下篇)

    前言 写了多年的LabVIEW程序,你是否面临这样的问题 总是在做一些重复的工作,感觉很没有意思: 总在不停的写代码,做类似的控件,实现相同的功能,丝毫没有成就感: 总在天加班,没有时间去提高自己; ...

  3. Spring MVC 框架的架包分析,功能作用,优点

    由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或是软件架构师,在学习和了解一个框架的时候,首先都应该知道的是这个框架的原理和与其有关j ...

  4. 搬-Android - Wi-Fi Tutorial[转]

    http://www.tutorialspoint.com/android/android_wi_fi.htm Android allows applications to access to vie ...

  5. canvas :曲线的面积图 加渐变效果

    document.body.innerHTML = '<canvas></canvas>' var cvs = document.querySelector("can ...

  6. POI读取Excel常见问题

    最近在做一个将excel导入到报表中的功能,使用了POI来实现,发现POI使用有诸多不便之处,先记录下来,以后可能考虑使用Openxml. 1. 数值类型处理 通过POI取出的数值默认都是double ...

  7. 浅谈P2P金融

    自从李总理开发互联网大会,提出“互联网+”,好像与互联网相在的所有事情都火起来了.上至80岁的老头,下至十多岁的孩童,都知道了这个词“互联网+”.虽然大家可能对”互联网+“的概念都只是一支半解,但是像 ...

  8. AFNetWorking

    目录: 1.为什么要用AFNetworking 2.AFNetworking的用法 一.为什么要用AFNetworking 在ios开发中,一般情况下,简单的向某个web站点简单的页面提交请求并获取服 ...

  9. CYQ.Data 批量添加数据性能测试(每秒千、万)

    今天有网友火晋地同学进了CYQ.Data官方群了,他正在折腾了一个各大ORM性能测试的比较的软件,如下图 折腾的种类也不少: 感觉这软件折腾的不错~~~值的期待~~~ 另外,他指出CYQ.Data 在 ...

  10. [转] Agile Software Development 敏捷软件开发

    原文作者:kkun 原文地址:http://www.cnblogs.com/kkun/archive/2011/07/06/agile_software_development.html 敏捷是什么 ...