题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4302 , 可以用线段树,也可以STL中的map,multiset,优先队列中的任何一个解决(可我只会线段树QAQ)。

  这道题的解决方法还是比较难想的,我是参考了kuangbin的博客才想到的方法,附链接:http://www.cnblogs.com/kuangbin/archive/2012/08/30/2664289.html


题目解法:

  用线段树来维护区间的最大值与最小值,设当前位置为cur,则对于每次询问,就可以求cur左边区间蛋糕位置的最大值与cur右边区间位置的最小值,选择离cur最近的那个位置即可,此时要更新cur,并且删掉该位置的一个蛋糕,并且调整运动的方向。

  这道题还有几个注意点:这道题的区间是从0到n的,所以具体解的时候要自己调整 ; 初始化线段树中的最大值与最小值 ; 每个位置的蛋糕不止一个,但是每次吃蛋糕的时候只会吃掉一个,所以要注意线段树更新的时候添加和删除蛋糕的个数(我是用一个cnt数组来存每个位置有几个蛋糕,这样可以避免出错) ;如果两边都没有蛋糕的话就停在当前位置 ;最后就是不要忘了运动的方向问题。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF INT_MAX
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = ;
const int maxn = + ;
const int N = + ;
int Max[maxn << ] , Min[maxn << ] , cnt[maxn << ];
void PushUp(int rt)
{
Max[rt] = max(Max[rt << ] , Max[rt << | ]);
Min[rt] = min(Min[rt << ] , Min[rt << | ]);
}
void build(int l , int r , int rt)
{
if(l == r) {
cnt[rt] = ;
Max[rt] = ;
Min[rt] = INF;
return;
}
int m = (l + r) >> ;
build(lson);
build(rson);
PushUp(rt);
}
void update(int pos , int x , int l , int r , int rt)
{
if(l == r) {
if(x) { //添加一个
Max[rt] = x;
Min[rt] = x;
cnt[rt]++;
} else {   //删除一个
if(cnt[rt] == ) {
Max[rt] = ;
Min[rt] = INF;
}
cnt[rt]--;
}
return;
}
int m = (l + r) >> ;
if(pos > m)
update(pos , x , rson);
else
update(pos , x , lson);
PushUp(rt);
}
int query_max(int L , int R , int l , int r , int rt)
{ //询问[L , R]区间的最大值
if(L <= l && R >= r) {
return Max[rt];
}
int m = (l + r) >> ;
if(R <= m)
return query_max(L , R , lson);
else if(L > m)
return query_max(L , R , rson);
else
return max(query_max(L , R , lson) , query_max(L , R , rson));
}
int query_min(int L , int R , int l , int r , int rt)
{ //询问[L , R]区间的最小值
if(L <= l && R >= r) {
return Min[rt];
}
int m = (l + r) >> ;
if(R <= m)
return query_min(L , R , lson);
else if(L > m)
return query_min(L , R , rson);
else
return min(query_min(L , R , lson) , query_min(L , R , rson));
}
void right(int &ans , int &dir , int &cur , int MIN , int n)
{ //向右移动到MIN位置
ans += MIN - cur;
dir = ;
cur = MIN;
update(MIN , , , n + , ); //删掉MIN位置一个蛋糕
}
void left(int &ans , int &dir , int &cur , int MAX , int n)
{ //向左移动到MAX位置
ans += cur - MAX;
dir = ;
cur = MAX;
update(MAX , , , n + , ); //删掉MAX位置一个蛋糕
}
int main()
{
int T , i , n , m , p , ch;
int ans , cur , dir; //结果 , 当前位置 , 运动方向
cin >> T;
for(int k = ; k <= T ; k++)
{
ans = ;
cur = dir = ;
scanf("%d %d" , &n , &m);
build( , n + , );
while(m--) {
scanf("%d" , &ch);
if(!ch) {
scanf("%d" , &p);
update(p + , p + , , n + , );
} else {
int MAX = query_max( , cur , , n + , );
int MIN = query_min(cur , n + , , n + , );
if(MAX == && MIN == INF) {
continue;
} else if(MAX != && MIN == INF) {
left(ans , dir , cur , MAX , n);
} else if(MAX == && MIN != INF) {
right(ans , dir , cur , MIN , n);
} else {
if(MIN - cur < cur - MAX) {
right(ans , dir , cur , MIN , n);
} else if(MIN - cur > cur - MAX) {
left(ans , dir , cur , MAX , n);
} else {
if(dir) {
right(ans , dir , cur , MIN , n);
} else {
left(ans , dir , cur , MAX , n);
}
}
}
}
}
printf("Case %d: %d\n" , k , ans);
}
return ;
}

  PS:等学了STL就用STL把这个题给解决了

  

HDU4302 线段树的更多相关文章

  1. hdu4302 set或者线段树

    题意:       一条蛇生活在一个管子里,然后管子上面的某些位置会一次出现食物,每次蛇都会吃最近的食物,吃完之后就原地不动,等待下一次吃食物,如果有两个食物距离蛇一样远并且都是最近的,那么蛇不会掉头 ...

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

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

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

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

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

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

  5. codevs 1080 线段树点修改

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

  6. codevs 1082 线段树区间求和

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

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

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

  8. CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作 分析:线段树 线段树的每个节点表示(f[i],f[i-1])这 ...

  9. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

随机推荐

  1. asp.net 防止二次提交 以及UseSubmitBehavior属性-转

    页面上有一个按钮,点击之后提交表单,如果什么都不管的话,用户可以在服务器响应完成之前再次点击,这样就出现了二次提交,后果可大可小. 那么我们应该防止二次点击,就要在用户点第一次之后马上Disable这 ...

  2. Cocos creator之javascript闭包

    .什么是闭包? 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.闭包的特点: 1. 作为一个函数变量的一个引用,当函数返回 ...

  3. ProtoBuf练习

    环境设置 项目地址 https://github.com/silvermagic/ProtoBufDev.git 操作系统 64位 Fedora 24 安装protobuf $ git clone h ...

  4. 萌新在线模板--keyboarder_zsq

    好像马上就要出去打铁了QAQ,所以是不是要做个模板带过去也玩一玩? 那就做吧... 标题就设为萌新模板吧...各种萌新讲解对吧.... 图论 拓扑排序 最短路 最小生成树 二分匹配 强连通Tarjan ...

  5. cookie中存取中文字符

    1.存入中文: Cookie c = new Cookie("username", java.net.URLEncoder.encode(name,"utf-8" ...

  6. PHP爬虫入门--简单的登录抓取内容

    给同事写一个小工具,抓取月报表然后统计加工.第一反应是做一个爬虫把需要的表和图抓下来,这样就不用再自己去连数据库然后组织表格生成图片之类的. 以上为背景 PHP 写爬虫 说实话我也想用Python的, ...

  7. .txt文件转换到Excel

    背景    前几天,自己在实验室里做实验,我们的大偶像肖老师看见我了,把我宣到他的办公室,问我,这个怎么办.都是数字,两列数字,怎么排版到Excel上也显示两列数字.Oh My God! 这个我怎么知 ...

  8. click点击事件先后顺序的问题

    //页面加载时,每秒钟调用一次var times = setInterval("loadFlws()","1000"); function loadFlws() ...

  9. Spring ThreadPoolTaskExecutor队列满的异常处理

    <!-- 配置线程池 --> <bean id="threadPool" class="org.springframework.scheduling.c ...

  10. express知识点

    本篇文章主要内容 1.用Express在系统文件夹内搭建一个服务器 2.Express的路由(来自 Express 文档) 3.Express的中间件(这才是关键) 4.Express的一些零碎的知识 ...