题意:营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况: 该天的最小波动值 当最小波动值越大时,就说明营业情况越不稳定。 而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。 第一天的最小波动值为第一天的营业额。

分析:

1、伸展树无论插入,删除等操作之后都要进行伸展操作,而伸展操作是不破坏伸展树的有序性的。

2、因此每当插入一个新结点,并通过伸展操作将其旋转到根结点后,与该结点值相差最小的一定是它的前驱结点值或后继结点值,两者取最小值即可。

3、前驱结点和后继结点的查找遵循“将二叉查找树进行中序遍历后可得有序序列”的原则。

前驱结点--该结点的左子结点的子树中最右端的结点。

后继结点--该结点的右子结点的子树中最左端的结点。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define lowbit(x) (x & (-x))
const double eps = 1e-8;
inline int dcmp(double a, double b){
if(fabs(a - b) < eps) return 0;
return a > b ? 1 : -1;
}
typedef long long LL;
typedef unsigned long long ULL;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const int MAXN = 32767 + 10;
const int MAXT = 10000 + 10;
using namespace std;
int root;//根结点标号,初始时是值为0的虚设根结点
int cnt;
int child[MAXN << 2][2];//左右子结点标号,按输入顺序从1开始依次标号
int value[MAXN << 2];//结点值
int pre[MAXN << 2];//父结点标号
void newNode(int &node, int fa, int x){
node = ++cnt;
pre[node] = fa;
value[node] = x;
child[node][0] = child[node][1] = 0;
}
void Rorate(int x, int dir){//dir:1--右旋,0--左旋
int y = pre[x];//y是x的父结点,该函数内以下注释以右旋为例
child[y][!dir] = child[x][dir];//将x的右子结点作为y的左子结点
pre[child[x][dir]] = y;//让x的右结点认y做父结点
if(pre[y]){//若y的父结点不是虚设根结点,则让y的父结点认x做子结点,左右取决于y原先是其父结点的左右子结点
child[pre[y]][child[pre[y]][1] == y] = x;
}//若y的父结点是虚设根结点,则y无所谓左右子结点,此时只需要立x为真正的根结点即可,真正根结点的一大标志是父结点标号为0
pre[x] = pre[y];//让x认y的父结点为父结点
child[x][dir] = y;//将y作为x的右子结点
pre[y] = x;//让y认x为父结点
}
void splay(int x, int goal){
while(pre[x] != goal){
int y = pre[x];
if(pre[y] == goal){//单旋
Rorate(x, child[y][0] == x);
}
else{
int dir = (child[pre[y]][0] == y);//y的旋转方向
if(child[y][dir] == x){//之字形旋转
Rorate(x, !dir);
Rorate(x, dir);
}
else{//一字形旋转
Rorate(y, dir);
Rorate(x, dir);
}
}
}
if(goal == 0) root = x;//更新根结点标号
}
int getPre(int x){//求前驱结点值
int tmp = child[x][0];
if(tmp == 0) return -1;//前驱结点为虚设根结点或不存在
while(child[tmp][1]) tmp = child[tmp][1];
return value[tmp];
}
int getSuc(int x){//求后继结点值
int tmp = child[x][1];
if(tmp == 0) return -1;////后继结点为虚设根结点或不存在
while(child[tmp][0]) tmp = child[tmp][0];
return value[tmp];
}
bool Insert(int x){
if(!root){
newNode(root, 0, x);
}
else{
int tmp = root;
if(value[tmp] == x){//树中已存在该结点值,不必再插入
splay(tmp, 0);
return false;
}
while(child[tmp][x > value[tmp]]){//child[tmp][0]--左,child[tmp][0]--右
tmp = child[tmp][x > value[tmp]];
if(value[tmp] == x){//树中已存在该结点值,不必再插入
splay(tmp, 0);
return false;
}
}
newNode(child[tmp][x > value[tmp]], tmp, x);
splay(child[tmp][x > value[tmp]], 0);
}
return true;
}
int main(){
int n;
scanf("%d", &n);
int x, ans = 0;
for(int i = 0; i < n; ++i){
scanf("%d", &x);
if(!i){
Insert(x);
ans += x;
}
else{
if(Insert(x)){
int prenode = getPre(root);
int sucnode = getSuc(root);
int tmp = INT_INF;
if(prenode != -1) tmp = min(tmp, x - prenode);
if(sucnode != -1) tmp = min(tmp, sucnode - x);
ans += tmp;
}
}
}
printf("%d\n", ans);
return 0;
}

  

HYSBZ - 1588 营业额统计 (伸展树)的更多相关文章

  1. HYSBZ 1588 营业额统计 (Splay树)

    题意:给出一个公司每一天的营业额,求每天的最小波动值之和.该天的最小波动值= min { 绝对值| 该天以前某一天的营业额-该天的营业额 | }.第一天的最小波动值就是其自己. 思路:Splay伸展树 ...

  2. HYSBZ 1588 营业额统计

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1588 题意:详见题面,中文 思路:平衡树的模板题. 可用Treap,Splay,Scape ...

  3. (HYSBZ)BZOJ 1588 营业额统计

    营业额统计 Time Limit: 5000MS   Memory Limit: 165888KB   64bit IO Format: %lld & %llu Description 营业额 ...

  4. BZOJ 1588 营业额统计

    Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...

  5. BZOJ 1588 营业额统计 set

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1588 题目大意: 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交 ...

  6. bzoj 1588营业额统计(HNOI 2002)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1588 splay  bottom-up的数组实现. 题意就是给你一组数,求每个数与在其前面且与其最相 ...

  7. BZOJ 1588 营业额统计 Splay

    主要操作为Splay中插入节点,查找前驱和后继节点. 1: #include <cstdio> 2: #include <iostream> 3: #include <c ...

  8. [bzoj] 1588 营业额统计 || Splay板子题

    原题 给出一个n个数的数列ai ,对于第i个元素ai定义\(fi=min(|ai-aj|) (1<=j<i)\),f1=a1,求\(/sumfi\) Splay板子题. Splay讲解:h ...

  9. 1588. [HNOI2002]营业额统计【平衡树-splay 或 线段树】

    Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...

随机推荐

  1. 执行SQL时出现: ORDER BY clause is not in GROUP BY clause and contains nonaggregated c

    注意: 采用navicat新建数据库时,需要将编码方式设置为,字符集:utf8 -- UTF-8 Unicode ,排序规则:utf8_general_ci 在运行sql语句时,出现以下问题: [Er ...

  2. PostgreSQL存取jsonb

    从PostgreSQL 9.3开始,json就成了postgres里的一种数据类型,也就是和varchar.int一样,我们表里的一个字段的类型可以为json了. 与此同时,postgres还提供了j ...

  3. windows 10 遥控操作和传输文件

    传输文件命令 scp file user@192.168.1.1:/home/           file文件传到192.168.1.1/home/目录下 scp -r directory user ...

  4. Centos7 nginx配置多虚拟主机过程

    一.前提准备 1.已经安装好了的Centos7服务器 2.ip 为192.168.1.209   [本次的配置ip] 3.确定防火墙等已经关闭 二.nignx配置文件参数详解 要配置多台虚拟主机,就需 ...

  5. redis 之redis持久化rdb与aof

    redis是内存型的数据库 重启服务器丢失数据 重启redis服务丢失数据 断电丢失数据 Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题,Redis提供了两种 ...

  6. NetCore Web项目目录结构说明

    目录结构说明 目录/文件 说明 依赖项 ASP.NET Core 开发.构建和运行过程中的依赖想,一般都是 NuGet 包和一些 SDK Properties 配置,存放了一些 .json 文件用于配 ...

  7. vim学习--usr03 moving around

    Word movement 小写的"w""ge""e""b" w表示向后移动到一个单词开头 ge表示向前移动到一个单词末 ...

  8. Android中利用正则表达式验证手机号是否合法

    利用正则表达式来验证手机号是否合法,现在我们简单使用一下,这个在实际的应用中很实用. 例:在输入框中输入手机号,判断是否合法, MainActivity中: package com.example.m ...

  9. android7.0关于TelephonyManager.getDeviceId()返回null的问题

    在android7.0的系统下发现TelephonyManager.getDeviceId()在权限允许的情况下取得返回值也为null,解决方法如下: public static String get ...

  10. Linux CentOS7 VMware find命令、文件名后缀

    一.find命令 Linux系统中的 find 命令在查找文件时非常有用而且方便.它可以根据不同的条件来查找文件,例如权限.拥有者.修改日期/时间.文件大小等等.在这篇文章中,我们将学习如何使用 fi ...