营业额统计(Treap的简单应用)

Treap的简单应用

题目链接

题意:
设第 i i i 天的营业额为 a i a_i ai,则第 i i i 天( i ≥ 2 i \ge 2 i2)的最小波动值 f i f_i fi 被定义为:
f i = m i n 1 ≤ j < i ∣ a i − a j ∣ f_i=min_{1 \le j < i}|a_i-a_j| fi=min1j<iaiaj
求出每一天的 f i f_i fi总和,其中: f 1 = a 1 f_1 = a_1 f1=a1

Sol:
建立平衡树,查询每天营业额在平衡树的前驱后继与之比较统计

code:

#include <bits/stdc++.h>
using namespace std;
const int N = 100010, INF = 1e8;
int n;
struct Node{
    int l, r;
    int key, val;
}tr[N];
int root, idx;
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;
}
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;
    if(tr[p].key > key ) return get_prev(tr[p].l, key);
    return max(tr[p].key, get_prev(tr[p].r, key));
}
int get_next(int p, int key)
{
    if(!p) return INF;
    if(tr[p].key < key) return get_next(tr[p].r, key);
    return min(tr[p].key, get_next(tr[p].l, key));
}
int main()
{
    build();
    scanf("%d", &n);
    
    int res = 0;
    for(int i=1; i <= n; ++i) {
        int x;
        scanf("%d", &x);
        if(i == 1){
            res += x;
            insert(root, x);
        }
        else {
            res += min(x - get_prev(root, x), get_next(root, x) - x);
            insert(root, x);
        }
    }
    printf("%d\n", res);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W⁡angduoyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值