算法竞赛进阶指南---0x49(平衡树) 营业额统计

题面

在这里插入图片描述

输入样例

6
5
1
2
5
4
6

输出样例

12

在这里插入图片描述

题解

  1. 这道题的意思就是对于 ai ,在前i个数中找一个与ai差值最小的数,做法还是很多的,我们可以直接用set做,也可以用邻接表做,还可以用treap做,代码是treap的
  2. 这题就是用treap找一个前驱(这里不是严格小于,因为等于才是最优解,模板代码看具体),然后找一个后继(也不是严格大于),然后判断前驱和后继哪个和当前值的差值是最小的即可
  3. 因为还是平衡树的模板,这里就不解释了,看模板点这里

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int INF = 1e7;

int n, a;
int root, idx;

struct Node {
    int l, r;
    int key, val;
} tr[N];


int get_node(int key) {
    tr[++idx].key = key;
    tr[idx].val = rand();
    return idx;
}

void zig(int &p) {  //右旋
    int q = tr[p].l;
    tr[p].l = tr[q].r, tr[q].r = p, p = q;
}

void zag(int &p) { //左旋
    int q = tr[p].r;
    tr[p].r = tr[q].l, tr[q].l = p, p = q;
}

void build() {
    get_node(-INF);
    get_node(INF);
    root = 1;
    tr[1].r = 2;
    if (tr[2].val > tr[1].val) zag(root);
}

void insert(int &p, int key) {
    if (!p) p = get_node(key);
    else if (tr[p].key == key) return;
    else if (tr[p].key > key) {
        insert(tr[p].l, key);
        if (tr[tr[p].l].val > tr[p].val) zig(p);
    } else {
        insert(tr[p].r, key);
        if (tr[tr[p].r].val > tr[p].val) zag(p);
    }
}

int get_prev(int p, int key) {   //找前驱
    if (!p) return -INF;
    else if (tr[p].key == key) return tr[p].key;
    if (tr[p].key >= key) return get_prev(tr[p].l, key);
    else return max(tr[p].key, get_prev(tr[p].r, key));
}

int get_next(int p, int key) {  //找后继
    if (!p) return INF;
    else if (tr[p].key == key) return tr[p].key;
    if (tr[p].key <= key) return get_next(tr[p].r, key);
    else return min(tr[p].key, get_next(tr[p].l, key));
}


int main() {

    build();
    cin >> n;
    ll res = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a;
        if (i == 1) {
            res += a;
        } else {
            res += min(abs(a - get_prev(root, a)), abs(get_next(root, a) - a));
        }
        insert(root, a);
    }
    cout << res << endl;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值