[Splay模板题]BZOJ1588

本文介绍了一种使用Splay树(伸展树)进行高效数据查询的方法,通过实现插入、查找前驱和后继的功能,提高了数据处理速度。文章详细解释了Splay树的旋转、更新和维护过程,并通过一个具体的示例程序展示了如何利用Splay树来找到与给定数值差最小的前驱或后继。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很朴素的找前驱和后继,感觉set完全可以做的咳咳。

用来练练splay吧……

#include <bits/stdc++.h>
#define lchild(x) (T[x].ch[0])
#define rchild(x) (T[x].ch[1])
#define fa(x) (T[x].fa)
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int n,cnt,root;
ll ans=1e18;
struct node{
    int val,ch[2],num,sz,fa;//权值,孩子,该权值个数,子树中所有权值个数,父亲
}T[maxn];
inline int newnode(int u,int fa){
    T[++cnt].fa=fa;T[cnt].val=u;//是cnt不是u
    T[cnt].sz=T[cnt].num=1;
    return cnt;
}
bool ident(int x){return lchild(fa(x))==x?0:1;}
void link(int x,int fa,int dir){T[fa(x)=fa].ch[dir]=x;}
void update(int x){ T[x].sz=T[lchild(x)].sz+T[rchild(x)].sz+T[x].num;}
void rotate(int x){
    int dir=ident(x),Y=fa(x),Z=fa(Y);
    link(T[x].ch[dir^1],Y,dir);
    link(x,Z,ident(Y));
    link(Y,x,dir^1);
    update(Y);update(x);
}
void splay(int x,int to){
    to=fa(to);
    while(fa(x)!=to){
        if(fa(fa(x))==to)rotate(x);
        else if(ident(x)==ident(fa(x))) rotate(fa(x)),rotate(x);
        else rotate(x),rotate(x);
    }
    root=x;
}
void insert(int x){
    if(!root) root=newnode(x,0);
    else{
        int now=root;
        while(1){
            T[now].sz++;
            if(T[now].val==x){ T[now].num++,splay(now,root);return;}
            int dir=T[now].val<x?1:0;
            if(!T[now].ch[dir]){
                splay(T[now].ch[dir]=newnode(x,now),root);
                return;
            }
            now=T[now].ch[dir];
        }
    }
}
int get(int now,int dir){//dir==0找前驱,dir==1找后继,//此处是要找的now已经是根的情况下
    if(T[now].num>1) return T[now].val;//因为前面可能有相等,所以有这句
    now=T[now].ch[dir];
    if(!now) return -1;
    while(T[now].ch[dir^1]) now=T[now].ch[dir^1];
    return T[now].val;
}
/*
int getpre(int now){//此处是要找的now已经是根的情况下
    if(T[now].num>1) return T[now].val;//因为前面可能有相等,所以有这句
    now=lchild(now);
    if(!now) return -1;
    while(rchild(now)) now=rchild(now);
    return T[now].val;
}
int getpost(int now){
    if(T[now].num>1) return T[now].val;
    now=rchild(now);
    if(!now) return -1;
    while(lchild(now)){
        now=lchild(now);
    }
    return T[now].val;
}
*/
int main(){//对于每个x找到前面的数中与之差最小的数
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        insert(x);
        if(i==1){ans=x;continue;}
        int pre=get(root,0),post=get(root,1),tans=1e9;
        if(~pre) tans=x-pre;
        if(~post) tans=min(tans,post-x);
        ans+=tans;
    }
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值