Acwing 265. 营业额统计

解题思路:本题解题思路主要有两种,一种是运用STL中的set,一种是用平衡树。

先来讲一下如何用set来实现,因为我们都知道set具有能够维护一个由相同元素组成的有序序列,但每个元素只能出现一次,当输入元素的时候,如果当前元素是第一个元素,那么答案直接加上该元素,如果不是第一个元素,利用set自带的lower_bound()函数找到第一个大于等于当前元素的数,然后我们还需要找到小于当前元素最大的数,如果说我们通过lower_bound()函数找到的数与当前元素的值不相等的话,那么找到的元素的上一个值就是小于当前元素的最大值了,当然如果找到的元素和当前元素恰好相等的话,那波动就是0了,可以直接不用管,因为加也是加0。

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
const int N =3e5+10;
int n;
int a[N];
set<int>s; 
set<int>::iterator k1,k2;
int main()
{
    cin>>n;
    cin>>a[1];
    long long ans=a[1];
    s.insert(192608170);//这里首先要往set里插入上下界,防止后面调用lower_bound()函数找大于等于当前数的最小数和小于当前数的最大数的时候发生边界问题 
    s.insert(-192608170);
    s.insert(a[1]);
    for(int i=2;i<=n;i++)
    {
        cin>>a[i];
        int x=a[i];
        k1=s.lower_bound(x);
        if(*k1!=x)
        {
           k2=k1;
           k2--;
            ans+=min(abs(x-*k1),abs(x-*k2));
        }
        
        s.insert(a[i]);
    }
    cout<<ans<<endl;
    return 0;
}

第二种做法就是用平衡树来做。在我的上一篇关于平衡树的博客中提到过平衡树的几个基本操作http://t.csdn.cn/GAuCkicon-default.png?t=M276http://t.csdn.cn/GAuCk,这个题就相当于给我们一个数,让我们每次在插入一个数前,先找到小于等于当前数的最大值和大于等于当前数的最小值,求出与当前数的最小差值加入到答案中,然后再将这个数插入到平衡树中,相比于第一种做法代码要长了很多。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=4e5+10,INF=1e8;
struct node{
    int l,r;
    int key,val;
}tr[N];
int n,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()
{
    root=get_node(-INF);
    tr[root].r=get_node(INF);
    if(tr[tr[root].r].val>tr[root].val)
    zag(root);
}
void insert(int &p,int key)
{
    if(!p)
    p=get_node(key);
    if(tr[p].key==key)
    return ;
    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_pre(int p,int key)//找到小于等于key的最大数
{
    if(!p)
    return -INF;
    if(tr[p].key>key)
    return get_pre(tr[p].l,key);
    else
    return max(tr[p].key,get_pre(tr[p].r,key));
}
int get_next(int p,int key)//找到大于等于key的最小数
{
    if(!p)
    return INF;
    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()
{
    cin>>n;
    build();
    long long res=0;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        if(i==1)
        res+=x;
        else
        res+=min(x-get_pre(root,x),get_next(root,x)-x);
        insert(root,x);
    }
    cout<<res<<endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值