Treap(一)——#10143. 「一本通 4.6 例 1」营业额统计

题目链接:https://loj.ac/problem/10143
解题思路
Treap模板题,我们发现对于每次ai,只需要找当前序列中比其大的最小的那个,和比其小的最大的那个,然后取差值的最小值加上去即可。所以需要用到Treap的插入,找前驱和后继即可。如果有相同元素,不受影响,不需要再插入了。之后套模板即可。
AC代码

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
int tot,rt;
const int N=(1<<15)+5;
const int inf=0x3f3f3f3f;
struct node
{
    int lc,rc,fa,pos,vis;
    #define lc(x) t[x].lc
    #define rc(x) t[x].rc
    #define fa(x) t[x].fa
    #define pos(x) t[x].pos //pos(x)为x的优先级
    #define vis(x) t[x].vis
}t[N];
inline void Zig(int &x)//右旋
{
    int y=lc(x);
    lc(x)=rc(y),rc(y)=x;
    x=y;
}
inline void Zag(int &x)//左旋
{
    int y=rc(x);
    rc(x)=lc(y),lc(y)=x;
    x=y;
}
inline void Insert(int &x,const int vi)//插入新元素
{
    if(!x)
    {
        vis(x=++tot)=vi,pos(x)=rand();
        return ;
    }
    if(vi<vis(x))
    {
        Insert(lc(x),vi);
        if(pos(lc(x))<pos(x))
        Zig(x);
    }
    else
    {
        Insert(rc(x),vi);
        if(pos(rc(x))<pos(x))
        Zag(x);
    }
}
inline int QueryPre(const int vi)//求前驱
{
    int x=rt,pr=-inf;
    while(x)
    {
        if(vi>=vis(x))
        pr=vis(x),x=rc(x);
        else
        x=lc(x);
    }
    return pr;
}
inline int QuerySuf(const int vi)//求后继
{
    int x=rt,sf=inf;
    while(x)
    {
        if(vi<=vis(x))
        sf=vis(x),x=lc(x);
        else
        x=rc(x);
    }
    return sf;
}
inline int get()//读入优化
{
    char c;
    int sign=1;
    while((c=getchar())<'0'||c>'9')//c=getchar()每次读入一个字符
    if(c=='-')sign=-1;//判断是否出现负数情况
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=res*10+c-'0';
    return res*sign;
}
/*void dfs(int x)
{
    if(x)
    cout<<x<<" "<<vis(x)<<endl;
    if(lc(x))
    dfs(lc(x));
    if(rc(x))
    dfs(rc(x));
}
*/
int main()
{
    int n,k,x,y,ans;
    n=get();
    //cout<<n<<endl;
    Insert(rt,ans=get());
    //cout<<"ans "<<ans<<endl;
    while(--n)
    {
        k=get();
        x=QueryPre(k);
        y=QuerySuf(k);
        ans+=min(k-x,y-k);
        //cout<<"k x y "<<k<<" "<<x<<" "<<y<<endl;
        //cout<<"ans "<<ans<<endl;
        Insert(rt,k);
    }
    //dfs(1);
    printf("%d\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值