[HNOI2004]宠物收养所
Splay求前驱与后继,然后累加和即可。
书上的Splay求x的前驱与后继需要插入x之后才能求得前驱与后继。删除操作时把x与前驱或者后继删除即可。
#include <cstdio> #include <algorithm> #include <vector> #include <cstdlib> #include <cstring> #include <cmath> #include <string> using namespace std; typedef int Comparable; struct Node { Node *left, *right; int element; Node(int v=0, Node *lt=0, Node *rt=0):element(v),left(lt),right(rt) {} }; Node *null = new Node(); void rotateWithLeftChild(Node *&t) { Node *k = t->left; t->left = k->right; k->right = t; t = k; } void rotateWithRightChild(Node *&t) { Node *k = t->right; t->right = k->left; k->left = t; t = k; } void splay(Node *&t, const Comparable &x) { Node *leftTreeMax, *rightTreeMin; static Node head; head.left = head.right = null; leftTreeMax = rightTreeMin = &head; null->element = x; for(;;) { if(x < t->element) { if(x < t->left->element) rotateWithLeftChild(t); if(t->left == null) break; //Link Right rightTreeMin->left = t; rightTreeMin = t; t = t->left; } else if(x > t->element) { if(x > t->right->element) rotateWithRightChild(t); if(t->right == null) break; //Link left leftTreeMax->right = t; leftTreeMax = t; t = t->right; } else break; } leftTreeMax->right = t->left; rightTreeMin->left = t->right; t->left = head.right; t->right = head.left; } int insert(Node *&root, const Comparable &x) { Node* newNode = new Node(x); if(root == null) { newNode->left = newNode->right = null; root = newNode; return 0; } splay(root, x); if(x < root->element) { newNode->left = root->left; newNode->right = root; root->left = null; root = newNode; } else if(x > root->element) { newNode->right = root->right; newNode->left = root; root->right = null; root = newNode; } else return -1; newNode = NULL; return 1; } void printTree(Node *o) { if(o != null) { printf("%d ", o->element); printTree(o->left); printTree(o->right); } } void remove(Node *&o, int x) { splay(o, x); if(o->element != x) return ; Node *newTree; if(o->left == null) newTree = o->right; else { newTree = o->left; splay(newTree, x); newTree->right = o->right; } delete o; o = newTree; } Node *findMin(Node *o) { if(o == null) return null; while(o->left != null) o = o->left; return o; } Node *findMax(Node *o) { if(o == null) return null; while(o->right != null) o = o->right; return o; } Node *predecessor(Node *o, int x) { splay(o, x); return findMax(o->left); } Node *successor(Node *o, int x) { return findMin(o->right); } /////////////////////// int n; const int INF = 0x3f3f3f3f; void readint(int &x) { char c = getchar(); while(!isdigit(c)) c = getchar(); x = 0; while(isdigit(c)) { x = x*10+c-'0'; c = getchar(); } } int main() { while(~scanf("%d", &n)) { Node *root = null; root->left = null; root->right = null; int ans = 0, flag = -1; for(int i = 1; i <= n; i++) { int cmd, x; scanf("%d%d", &cmd, &x); if(flag == -1) { insert(root, x); flag = cmd; } else if(flag == cmd) { insert(root, x); } else { int p = insert(root, x); if(p == -1) { remove(root, x); } else { Node *pre = predecessor(root, x); Node *next = successor(root, x); int t1 = pre != null? pre->element:INF; int t2 = next != null? next->element:INF; if(abs(t1-x) <= abs(t2-x)) { ans = (ans+abs(t1-x))%1000000; remove(root, t1); remove(root, x); } else { ans = (ans+abs(t2-x))%1000000; remove(root, t2); remove(root, x); } } if(root == null) flag = -1; } } printf("%d\n", ans%1000000); } return 0; }
Splay伸展树
Splay伸展树
Splay是二叉查找树,不是一颗平衡树,但可以通过自调整达到一种近似平衡的情况。Splay在连续M次操作中均摊时间复杂度是M*logn,其中n为节点的个数,M为操作的次数。Splay的操作与特点将在以下介绍。
- 当访问一个节点时,立即把当前访问的节点旋转到根节点,让访问(插入)的节点立马成为新的根节点。
- 旋转操作与AVL很像,有两种旋转,左旋、右旋。
- Splay操作有两种不同的实现方式。一种是自底向上的旋转,需要记录当前节点的父亲节点。另外一种是自顶向上的实现方式,不需要记录父亲节点。
- 由于Splay把当前访问的节点放在根节点,很容易求出当前节点的前驱与后继。
- Splay支持merge、split、findMin、findMax、predecessor、successor、insert、remove等操作。
- 在信息学竞赛中,Splay可以实现能实现线段树的所有的功能,即pushup、pushdown维护区间信息在Splay中用的很活,但Splay又支持快速的序列分离和合并,这是线段树做不到的。
- 验证自己手写的数据结构是否正确可以去OJ写一写用到该数据结构的题。
Treap树
最近在学高级数据结构,AVL、BST、SPLAY、Treap、红黑树等,能够快速实现AVL、BST、SPLAY、Treap,以及会利用简单变形解决某些问题就达到要求了。
大学计算机专业的学生,数据结构书上的所有数据结构能够快速实现,对计算机理论不至于精通,但要熟悉,随便提出一个基础理论至少不陌生。高数、现代、概率论都要达到熟悉的地步。
Treap,顾名思义,Tree+Heap的简称,与BST不同,节点还附加了一个随机优先级来平衡树,所以又带有堆的性质,可以证明最坏的查找、删除效率为O(logn),它可以做到set做不到的事,如快速求第K大值,以及求值x的名次,也被称作名次树。如果附加的优先级是固定的话,那么就成了笛卡尔树。