题意: 给你n个数,要求对于所有的i, 求出第i个数 和1------- i-1之间的数里找一个与第i 个数绝对值差值最小, 求所有的差值之和
做法: 对于第i个数v,把v 插入伸展树,若v存在就不插入,并把v所在的节点旋转到根,在通过根的左右子树找最接近的左右两个数,更新答案即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct node; node *null, *root; struct node { node *c[2], *fa; int sz, v; inline bool d() { return fa->c[1]== this; } inline void fix(int d, node *x) { c[d] = x, x->fa = this; } inline void rot() { node *y = fa, *z = y->fa; bool f = d(); z->fix(y->d(), this); y->fix(f, c[!f]); fix(!f, y); y->up(); } void splay(node *g) { while(fa != g) { node *y = fa, *z = y->fa; if(z == g) rot(); else if(y->d() == d()) y->rot(), rot(); else rot(), rot(); } up(); if(g==null) root = this; } void up() { sz = c[0]->sz + c[1]->sz+1; } int cmp(int x) const { if(x == v) return -1; return x > v; } }; const int maxn = 100005; node mem[maxn]; int tot; node* newNode(int v=0, node *fa=null) { node *x = &mem[tot++]; x->v = v, x->fa = fa; x->sz = 1, x->c[0] = x->c[1] = null; return x; } bool ins(node *&o, node *fa, int v, node *&ans) { if(o == null) { o = newNode(v, fa); ans = o; return 1; } int d = o->cmp(v); if(d == -1) { ans = o; return 0; } return ins(o->c[d], o, v, ans); } void init() { tot = 0; null = new node(), null->sz=0; root = null; } int pre(node *o) { if(o==null) return -1; if(o->c[1] != null) return pre(o->c[1]); return o->v; } int suf(node *o) { if(o==null) return -1; if(o->c[0] != null) return suf(o->c[0]); return o->v; } int main() { int n, v; scanf("%d%d", &n, &v); init(); root = newNode(v, null); int ans = v; for(int i = 1; i < n; i++) { if(scanf("%d", &v) == -1) v = 0; node *x; int t; t = ins(root, null, v, x); x->splay(null); if(!t) continue; int d = 1e9; if((t = pre(x->c[0])) != -1) d = min(d, v-t); if((t = suf(x->c[1])) != -1) d = min(d, t-v); ans += d; } printf("%d\n", ans); return 0; }
原文:http://blog.csdn.net/auto_ac/article/details/19137717