Treap模板

 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
inline ll read()
{
    ll ans = 0;
    char ch = getchar(), last = ' ';
    while(!isdigit(ch)) {last = ch; ch = getchar();}
    while(isdigit(ch))
    {
        ans = ans * 10 + ch - '0'; ch = getchar();
    }
    if(last == '-') ans = -ans;
    return ans;
}

int n, root = 0; //n种操作;root记录根节点是谁(因为进行某一操作后,根节点可能改变,所以要随时记录)
int cnt = 0, lson[maxn], rson[maxn]; //cnt:节点总数(即每一个节点的编号);lson[now],rson[now]:节点now的左右孩子
int val[maxn], ran[maxn], size[maxn], Cnt[maxn];//val[now]:节点now的权值;ran[now]:随机出来的优先级;size[now]:子树大小;
//Cnt[now]记录和val[now]相同的节点多少个(用来处理数字重复)
void update(int now)
{
    if(!now) return;
    size[now] = size[lson[now]] + size[rson[now]] + Cnt[now];
}
void right_rotate(int& Q)
{
    int P = lson[Q];
    lson[Q] = rson[P];            //这个和下面那句不能反
    rson[P] = Q;
    update(Q); update(P);
    Q = P;
}
void left_rotate(int& Q)
{
    int P = rson[Q];
    rson[Q] = lson[P];
    lson[P] = Q;
    update(Q); update(P);
    Q = P;
}
void insert(int& now, int v)//插入v
{
    if(!now)                //找到要插入的叶节点了
    {
        now = ++cnt;        //新建节点
        val[now] = v;
        size[now] = Cnt[now] = 1;
        ran[now] = rand();    //随机优先级
        return;
    }
    if(val[now] == v) Cnt[now]++;    //若树中已经有了该数,就直接Cnt[]++了
    else if(val[now] > v)        //说明在左子树
    {
        insert(lson[now], v);    //递归寻找
        if(ran[lson[now]] < ran[now]) right_rotate(now);
        //这一步放在了递归后面,说明此时节点已经插入好了(而且只是修改了左子树),那就判断并通过旋转维护堆
    }
    else
    {
        insert(rson[now], v);
        if(ran[rson[now]] < ran[now]) left_rotate(now);
    }
    update(now);
}
void del(int& now, int v)//删除v
{
    if(!now) return;
    if(val[now] == v)    //找到了该数
    {
        if(Cnt[now] > 1) //有重复
        {
            Cnt[now]--;
            update(now); return;
        }
        else if(lson[now] && rson[now])    //并没有旋转到根节点
        {
            left_rotate(now);     //只要选任意一棵子树旋转就行
            del(lson[now], v);    //这两句等价于right_rotate(now); del(rson[now], v);
        }
        else                //代表只剩一个孩子了,那么就直接用他的孩子代替他,相当于把他删除
        {
            now = lson[now] | rson[now];    //等价于now = lson[now] ? lson[now] : rson[now]
            update(now); return;
        }
    }
    else if(val[now] > v) del(lson[now], v);        //没找到就接着找
    else del(rson[now], v);
    update(now);
}
int Find_id(int now, int v)//查询id排名
{
    if(!now) return 0;
    if(val[now] == v) return size[lson[now]] + 1;        //别忘加上自己
    if(val[now] > v) return Find_id(lson[now], v);
    else return Find_id(rson[now], v) + size[lson[now]] + Cnt[now];
}
int Find_num(int now, int id)//查询排名为id的数
{
    if(!now) return INF;
    if(size[lson[now]] >= id) return Find_num(lson[now], id);        //在左子树
    else if(id <= size[lson[now]] + Cnt[now]) return val[now];        //在左子树和自己,但因为左子树的已经走上面的语句了,就指自己
    else return Find_num(rson[now], id - size[lson[now]] - Cnt[now]);    //右子树,别忘减去(跟线段树找第k小挺像)
}
int Pre(int now, int v)//小于等于
{
    if(!now) return -INF;
    if(val[now] <= v) return max(val[now], Pre(rson[now], v));//前驱在右子树或是当前节点
    else return Pre(lson[now], v);
}
int Nex(int now, int v)//大于等于
{
    if(!now) return INF;
    if(val[now] >= v) return min(val[now], Nex(lson[now], v));//去掉前面的等号就变成大于了
    else return Nex(rson[now], v);
}

int main()
{
    n = read();
     int x=read(),sum=x;
    insert(root,x);
    while(--n)
    {
        x=read();
        sum+=min(x-Pre(root,x),Nex(root,x)-x);
        //cout<<Pre(root,x)<<endl;
        insert(root,x);
        //int d = read(), x = read();
    }
    printf("%d\n",sum);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值