Bzoj1588--Hnoi2002营业额统计
平衡树练习
每次插入一个数判断是否重复,重复则返回0,否则选出与它差最小的数返回差的绝对值
最小差必定是左子树中最大点或右子树中最小点或其祖先,找找就可以了
代码:
#include<bits/stdc++.h> #define MAXN 300005 #define MAXM 3005 #define INF 10000000000000LL #define MOD 998244353 #define LL long long using namespace std; inline int read() { int ret=0,f=1;char c=getchar(); while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();} while(c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();} return ret*f; } inline LL _abs(LL a) {return a>0?a:-a;} int n; struct node{ int son[2],par;LL v,r; }x[MAXN]; struct Treap{ int L,R,root,cnt; void init() { L=0;R=1;root=MAXN-5;cnt=0; x[MAXN-5].r=INF;x[MAXN-5].v=INF; } inline void rotate(int num,int p) { int pa=x[num].par; x[x[pa].par].son[x[x[pa].par].son[L]==pa?L:R]=num; x[pa].son[p^1]=x[num].son[p];if(x[num].son[p]) {x[x[num].son[p]].par=pa;} x[num].son[p]=pa;x[num].par=x[pa].par;x[pa].par=num; } int Insert(int v) { x[++cnt].v=v;x[cnt].r=rand()%MOD; int now=root,pre;LL le,ri; while(true) { if(v==x[now].v) {cnt--;return 0;} pre=v<x[now].v?L:R; if(!x[now].son[pre]) {x[now].son[pre]=cnt;x[cnt].par=now;break;} now=x[now].son[pre]; } now=cnt; while(true) { if(x[x[now].par].son[L]==now) pre=R;else pre=L; if(x[now].r>x[x[now].par].r) rotate(now,pre); else break; } le=x[now].son[L];ri=x[now].son[R]; while(x[le].son[R]) le=x[le].son[R]; while(x[ri].son[L]) ri=x[ri].son[L]; le=le?x[now].v-x[le].v:INF;ri=ri?x[ri].v-x[now].v:INF; now=x[now].par; if(le==ri&&le==INF&&now==root) return x[cnt].v; le=le<ri?le:ri; while(now) { le=le<_abs(x[now].v-x[cnt].v)?le:_abs(x[now].v-x[cnt].v); now=x[now].par; } return le; } }; int main() { srand(2333333); n=read();LL ret=0; Treap p;p.init(); for(int k,i=1;i<=n;i++) { k=read(); ret+=p.Insert(k); } printf("%lld\n",ret); return 0; }