题目地址: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. 服务器使用FTP命令行 无法传送文件 卡在150 Opening data channel for file transfer

    猜测,是因FTP服务器采用了主动模式,在创建数据传输通道时,服务器会以一个随机的端口,连接回来. 临时解决方案: 因不知道请求回来使用的哪个段的端口,因此,暂时关闭了防火墙.即能正常传输文件了.

  2. oracle连接问题【转载】

    SQL的四种连接-左外连接.右外连接.内连接.全连接   今天在看一个遗留系统的数据表的时候发现平时查找的视图是FULL OUT JOIN的,导致平时的数据记录要进行一些限制性处理,其实也可以设置视图 ...

  3. sublime_text_2 ubuntu下无法输入中文 解决方法

    参考资料:http://my.oschina.net/wugaoxing/blog/121281 环境配置:ubuntu 14.10 1.保存下述代码为 sublime_imfix.c 文件 /* s ...

  4. js判断undefined类型

    js判断undefined类型 if (reValue== undefined){    alert("undefined");    }  发现判断不出来,最后查了下资料要用ty ...

  5. 将 java 项目打包成可运行的 jar 包(main 函数带参数),并上传到 linux 服务器上运行

    一.概述 java项目有两种架构,一种是 B/S 架构的,一种是 C/S 架构的. 对于 B/S 架构来说,我们常见的 java ee 即是 B/S 架构,通常,开发人员会在本地进行开发,然后将项目打 ...

  6. <十二>JDBC_批量处理

    import java.sql.Connection;import java.sql.PreparedStatement;import org.junit.Test;import com.kk.jdb ...

  7. java学习中一些疑惑解答(2)

    (一)继承条件下构造方法的调用 以下面的源代码为例: package ktdemo; class Grandparent { public Grandparent() { System.out.pri ...

  8. Unity3D UGUI之ScrollView弹簧效果

    unity3d版本5.3.2p4 UGUI中ScrollView包含Viewport(Content) ScrollView包含脚本.其Movement Type一共3个选项.Elastic就是弹簧效 ...

  9. sql编写将时间转换年月日 时分格式

    SELECT SUBSTRING(CONVERT(varchar(100),时间字段, 22),0,15) AS aa  FROM  表名

  10. The Swiss Army Knife of Data Structures … in C#

    "I worked up a full implementation as well but I decided that it was too complicated to post in ...