[洛谷P2234, HNOI2002]营业额统计, fhq-treap

本文介绍了一个简单的方法来分析公司的营业额波动情况。通过使用fhq-treap数据结构,可以有效地计算每天的最小波动值,进而评估整体营业稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

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

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

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

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

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


这道题是比较简单的, 这次使用了fhq-treap, fhq-treap的优点是好写.
相对treap, 我觉得找前驱后继太繁琐了

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
struct Node{
    Node * left, * right;
    int value, priority;
    Node(){};
    Node(Node * l, Node * r, int v, int p): left(l), right(r), value(v), priority(p){};
};
typedef pair<Node *, Node *> pNN;
Node * null = new Node(), * root = null;
void print(Node * o){
    if(o == null){
        printf(" NULL ");
        return;
    }
    print(o->left);
    printf(" %d ", o->value);
    print(o->right);
}
pNN split_l(Node * o, int val){
    if(o == null){
        return make_pair(null, null);
    }
    pNN result;
    if(o->value <= val){
        result = split_l(o->right, val);
        o->right = result.first;
        result.first = o;
    }
    else{
        result = split_l(o->left, val);
        o->left = result.second;
        result.second = o;
    }
    return result;
}
pNN split_r(Node * o, int val){
    if(o == null){
        return make_pair(null, null);
    }
    pNN result;
    if(o->value < val){
        result = split_r(o->right, val);
        o->right = result.first;
        result.first = o;
    }
    else{
        result = split_r(o->left, val);
        o->left = result.second;
        result.second = o;
    }
    return result;
}
Node * merge(Node * left, Node * right){
    if(left == null){
        return right;
    }
    if(right == null){
        return left;
    }
    if(left->priority < right->priority){
        left->right = merge(left->right, right);
        return left;
    }
    else{
        right->left = merge(left, right->left);
        return right;
    }
}
int getMin(Node * o){
    while(o->left != null){
        o = o->left;
    }
    return o->value;
}
int getMax(Node * o){
    while(o->right != null){
        o = o->right;
    }
    return o->value;
}
void insert(int val){
    pNN first = split_l(root, val);
    pNN second = split_r(first.first, val);
    Node * node = new Node(null, null, val, rand());

    second.second = merge(second.second, node);
    root = merge(merge(second.first, second.second), first.second);
}
int getPre(int val){
    pNN first = split_l(root, val);
    pNN second = split_r(first.first, val);
    if(second.second != null){
        root = merge(merge(second.first, second.second), first.second);
        return second.second->value;
    }
    root = merge(merge(second.first, second.second), first.second);

    pNN tree = split_r(root, val);

    int rst = getMax(tree.first);
    root = merge(tree.first, tree.second);

    return rst;
}
int getNext(int val){
    pNN tree = split_l(root, val);

    int rst = getMin(tree.second);
    root = merge(tree.first, tree.second);

    return rst;
}
int main(){
    null->left = null->right = null;
    // insert(-0x3f3f3f3f), insert(0x3f3f3f3f);
    int n, tmp;
    scanf("%d", &n);
    scanf("%d", &tmp);
    insert(tmp);
    long long sum = tmp;
    print(root);
    printf("sum %lld\n", sum);
    for(int i = 1; i < n; ++i){
        scanf("%d", &tmp);
        sum += min(getNext(tmp) - tmp, tmp - getPre(tmp));
        insert(tmp);
    }
    printf("%lld\n", sum);
    return 0;
}
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值