BZOJ 1588 [HNOI2002]营业额统计

splay。

模仿别人的代码打的,加了一些注释

我很好奇排名第一的0s用了什么神奇的数结- -

#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 200005
using namespace std;
const int INF = 1<<29;
struct SplayTree
{
    int son[N][2], fa[N], siz[N], cnt[N], val[N], root, tot;
    void up(int x)
    {
        siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];
    }
    void rotate(int x, int flag)//flag 0左旋 1右旋
    {
        int y=fa[x];
        //分步处理,都是两行,一个改fa一个改son 
        //1.处理x的儿子 
        son[y][flag^1]=son[x][flag];
        fa[son[x][flag]]=y;
        //2.处理y的父亲 
        fa[x]=fa[y];
        if(fa[y])son[fa[y]][son[fa[y]][1]==y]=x;        
        //3.处理x和y 
        fa[y]=x;
        son[x][flag]=y; 
        up(y);
    } 
    void splay(int x, int goal)//将x旋到goal之下,goal=0表示x转为根 
    {
        while(fa[x]!=goal)
        {
            if(fa[fa[x]]==goal)//单旋 
                rotate(x,son[fa[x]][0]==x);
            else
            {
                int fax=fa[x], faxx=fa[fax], flag=(son[faxx][0]==fax);
                if(son[x][flag]==x)//双左右旋,双右左旋 
                {
                    rotate(x,!flag);
                    rotate(x,flag);
                } 
                else//双左左旋,双右右旋 
                {
                    rotate(fax,flag); //父亲单旋,以降低层数 
                    rotate(x,flag);
                }
            }
        } 
        up(x);
        if(goal==0)
            root=x;
    } 
    void add_node(int v, int fat) 
    {
        val[++tot]=v;
        son[tot][1]=son[tot][0]=0;
        fa[tot]=fat;
        son[fat][val[fat]<v]=tot;
        cnt[tot]=siz[tot]=1;
    }
    void init()
    {
        tot=0;
        root=1;
        add_node(INF,0);//实际上是一号节点 
        add_node(-1*INF,1); //实际上是二号节点
        //加入最值保证查找不出错 
        siz[1]=1;
    }
    void inser(int pre, int fat, int v)
    {
        if(!pre)
        {
            add_node(v,fat);
            splay(tot,0);
            return;
        }
        if(val[pre]==v)
        {
            cnt[pre]++;
            up(pre);
            splay(pre,0);
            return;
        }
        if(v>val[pre])inser(son[pre][1],pre,v);
        else inser(son[pre][0],pre,v);
        up(pre);
    }   
    void find_max(int &x, int pre, int v)
    {
        if(!pre)return;
        if(v<=val[pre])
        {
            x=val[pre];
            find_max(x,son[pre][0],v);
        }
        else
            find_max(x,son[pre][1],v);
    }
    void find_min(int &x, int pre, int v)
    {
        if(!pre)return;
        if(v>val[pre])
        {
            x=val[pre];
            find_min(x,son[pre][1],v);
        }
        else
            find_min(x,son[pre][0],v);
    }
}st;
int main()
{
    int n, a;
    st.init();
    scanf("%d",&n);
    scanf("%d",&a);
    st.inser(st.root,0,a);
    int ans=a;
    for(int i = 1; i < n; i++)
    {
        int pre1, pre2, now;
        scanf("%d",&a);
        st.find_max(pre1,st.root,a);
        st.find_min(pre2,st.root,a);
        now=min(abs(pre2-a),abs(pre1-a));
        ans+=now;
        st.inser(st.root,0,a); 
    }
    printf("%d\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值