P2234 [HNOI2002]营业额统计 , 平衡二叉树模板题

题目描述

Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。

Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:

当最小波动值越大时,就说明营业情况越不稳定。

而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。

第一天的最小波动值为第一天的营业额。

该天的最小波动值=min{|该天以前某一天的营业额-该天营业额|}。
输入格式

输入由文件’turnover.in’读入。

第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数ai(|ai|<=1000000) ,表示第i天公司的营业额,可能存在负数。
输出格式

输入输出样例
输入 #1

6 5 1 2 5 4 6

输出 #1

12

说明/提示

结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12
分析平衡二叉树模板题
也可以用线段树求解

#include<bits/stdc++.h>

using namespace std;
const int N = 32767 + 10;
typedef long long ll;

struct node{
    int height,data;    //data为结点权值,height为当前子树高度
    struct node* left,*right;    //左右孩子的结点地址
};

//获取以root为根节点的子树的当前height
int getHeight(node * root){
    if(root==NULL)  return 0;    //空结点高度为0
    return root->height;
}

//计算结点root的平衡因子
int getBalanceFactor(node *root){
    //左子树高度减去右子树高度
    return getHeight(root->left)-getHeight(root->right);
}

//更新结点root的高度
void updateHeight(node *root){
    if(root==NULL)  root->height=0;
    else{
        root->height=max(getHeight(root->left),getHeight(root->right))+1;
    }
}

node * newNode(int v){
    node *Node=new node;
    Node->data=v;
    Node->height=1;
    Node->left=Node->right=NULL;
    return Node;
}

//左旋操作
void L(node* &root){
    node * temp=root->right;
    root->right=temp->left;
    temp->left=root;
    updateHeight(root);    //记得更新结点的高度
    updateHeight(temp);
    root=temp;
}

//右旋操作
void R(node* &root){
    node * temp=root->left;
    root->left=temp->right;
    temp->right=root;
    updateHeight(root);
    updateHeight(temp);
    root=temp;
}

//插入权值为v的结点
void insert(node* &root,int v){
    if(root==NULL) {    //到达空结点
        root=newNode(v);
        return;
    }
    if(root->data>v){    //v比根节点的权值小
        insert(root->left,v);    //往左子树插入
        updateHeight(root);    //更新树高
        if(getBalanceFactor(root)==2){
            if(getBalanceFactor(root->left)==1){    //LL型
                R(root);
            }
            else if(getBalanceFactor(root->left)==-1){    //LR型
                L(root->left);
                R(root);
            }
        }
    }
    else{
        insert(root->right,v);    //往右子树插入
        updateHeight(root);    //更新树高
        if(getBalanceFactor(root)==-2){
            if(getBalanceFactor(root->right)==-1){    //RR型(!注意 此时平衡因子为-1)
                L(root);
            }
            else if(getBalanceFactor(root->right)==1){    //RL型
                R(root->right);
                L(root);
            }
        }
    }
}

void preorder(node *n){
        if(n==NULL) return;
        printf("%d\n",n->data);
        preorder(n->left);
        preorder(n->right);
}
int Find(node *root, int x)
{
    if(root->data == x)
        return x;
    else if((root->data > x && root->left == NULL) || (root->data < x && root->right == NULL))
        return root->data;
    else if(root->data > x && root->left != NULL)
    {
        int num = Find(root->left, x);
        return abs(root->data - x) > abs(num - x) ? num:root->data;
    }
    else if(root->data < x && root->right != NULL)
    {
        int num = Find(root->right, x);
        return abs(root->data - x) > abs(num - x) ? num:root->data;
    }
}
int a[N];
int main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    node *root = NULL;
    int n;
    cin >> n;
    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        if(i == 1)
        {
            ans += a[i];
        }
        else
        {
          //  cout << "---------" << endl;
          //  preorder(root);
          //  cout << "---------" << endl;
            int x = Find(root, a[i]);
           // cout << x << "***" << endl;
            ans += abs(a[i] - x);
        }
        insert(root, a[i]);
    }
    cout << ans << endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值