bzoj 1588

treap的裸题,查找最近的数其实和插入的方法是一样的,可以写在一起,然而影响不大也就懒得写了。

treap的思想就是把二叉搜索树改为随机顺序插入,这样就不会被数据卡成一条链了。

主要由一个旋转操作来维护。这个操作网上有很多,就不多说了。

一个节点有两个量:key,value。

value表示这个节点的值,key表示random出来的值,维护key的堆性质和value的二叉搜索树性质即可。

这样这棵树其实已经在插入前就定好了,由于key是随机的,所以插入及查询的期望时间复杂度为O(logn)。

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=32768;
int read(){
    char c; while(!isdigit(c=getchar()) && c!='-');
    int x=0,y=1; if(c=='-') y=-1; else x=c-'0';
    while(isdigit(c=getchar())) x=x*10+c-'0'; return x*y;
}
int ro,cnt,c[maxn][2],v[maxn],r[maxn];
void rotate(int &o,int d){
    int k=c[o][d];
    c[o][d]=c[k][d^1];
    c[k][d^1]=o; o=k;
}
void insert(int &o,int x){
    if(!o){r[o=++cnt]=rand(); v[o]=x;}
    else if(v[o]!=x){
        int to=x>v[o];
        insert(c[o][to],x);
        if(r[c[o][to]]>r[o]) rotate(o,to);
    }
}
int find(int o,int x){
    int res=2e9;
    while(o){
        res=min(abs(x-v[o]),res);
        o=c[o][x>v[o]];
    }
    return res;
}
int main(){
    int n=read(),ans=0;
    for(int i=1;i<=n;i+=1){
        int x=read();
        if(i==1) ans+=x; else ans+=find(ro,x);
        insert(ro,x);
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2017-10-24 14:37  或是七一  阅读(123)  评论(0编辑  收藏  举报