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; }