bzoj 1588 splay 模板

// 每插入一个点求它与树中的点的最小绝对值
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<string>
#define maxi 0x73ffffff
#define maxn 200005
#define LL long long
using namespace std;
struct splayTree{
       //关于树的备用的
       int son[maxn][2];//0为左儿子,1为右儿子
       int fa[maxn];// 该节点的父亲
       int rt,tot;//祖宗,节点数量
       int siz[maxn];//字数大小本题不需要

       inline void up(int i)
       {
            siz[i] = cnt[i]+siz[son[i][0]]+siz[son[i][1]];
       }
       inline void Rotate(int x,int flag)//flag 0 左旋,1右旋
       {
            int y = fa[x]; //y为x父
            son[y][!flag] = son[x][flag];
            fa[son[x][flag]] = y;//先处理x的儿子

            fa[x] = fa[y];
            if(fa[y])son[fa[y]][son[fa[y]][1]==y] = x; //再处理y的父亲

            fa[y] = x; //再处理 x和y
            son[x][flag] = y;
            up(y);

       }
       inline void splay(int x,int goal) //把x旋到goal后面
       {
           while(fa[x]!=goal)
           {
               if(fa[fa[x]]==goal)Rotate(x,son[fa[x]][0]==x);//单旋
               else{
                    int fax = fa[x],faxx = fa[fax];
                    int flag = (son[faxx][0]==fax);
                    if(son[fax][flag]==x) //双左右或双右左旋
                    {
                       Rotate(x,!flag);
                       Rotate(x,flag);
                    }
                    else //左左旋右右旋
                    {
                        Rotate(fax,flag);
                        Rotate(x,flag);
                    }
               }
           }
           up(x);
           if(goal==0)rt = x;
       }
       inline void visit(int x) //调试GG
       {
              printf("本点 %d 价值 %d 左二子 %d 右儿子 %d 祖宗 %d\n",x,va[x],son[x][0],son[x][1],rt);
              if(son[x][0])visit(son[x][0]);
              if(son[x][1])visit(son[x][1]);
       }
       //以上通用不用修改

       void addNode(int val,int far)
       {
             va[++tot] = val;
             son[tot][0] = son[tot][1] = 0;
             fa[tot] = far;
             son[far][val>=va[far]] = tot;
             cnt[tot] = siz[tot] = 1;
       }
       void init()
       {
            tot = 0,rt = 1;
            addNode(maxi,0);
            addNode(-1*maxi,1);
            siz[1] = 2;
       }
       void inser(int pre,int far,int val)//插入啊
       {
            if(!pre)//插入
            {
                addNode(val,far);
                splay(tot,0);
                return ;
            }
            if(va[pre]==val) //重复计数
            {
                cnt[pre]++;
                up(pre);
                splay(pre,0);
                return ;
            }
            if(val>=va[pre])inser(son[pre][1],pre,val);//继续寻找
            else inser(son[pre][0],pre,val);
            up(pre);
       }
       void findMax(int &x,int pre,int val)//查询大于等于val的最小值
       {
            if(!pre)return ;
            if(va[pre]>=val)
            {
                x = va[pre];
                findMax(x,son[pre][0],val);
            }
            else findMax(x,son[pre][1],val);
       }
       void findMin(int &x,int pre,int val)//查询小于val的最大值
       {
            if(!pre)return ;
            if(va[pre]<val)
            {
               x = va[pre];
               findMin(x,son[pre][1],val);
            }
            else findMin(x,son[pre][0],val);
       }
       int va[maxn],cnt[maxn];//va价值 cnt统计这个点的值有多少个
}st;
int main()
{
    int n,a;
    int ans = 0;
    st.init();
    scanf("%d",&n);
    scanf("%d",&a);
    st.inser(st.rt,0,a);
    n--;
    ans = a;
    while(n--)
    {
        int pre = 0,pre2;
        scanf("%d",&a);
        st.findMax(pre,st.rt,a);
        pre2 = abs(a-pre);
        st.findMin(pre,st.rt,a);
        pre2 = min(pre2,abs(a-pre));
        ans+=pre2;
        st.inser(st.rt,0,a);
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值