今天学习了一下AVL,顺便用AVL树 A掉了这道经典的题,以前用树状数组解过这个题,今天记录一下AVL的解法。如有错误之处欢迎指正,各位大牛不要笑话我。
该题需要用平衡树:定义这样的一颗平衡树,根节点大于等于左儿子节点,小于右儿子节点。(也可以规范的定义左儿子小于根,小于右儿子,但是要加入新的数据域)
为了球第K小,除了原本的height域以外加入一个size域,表示以当前节点为跟的子树有多少个节点。
操作1:数据域的维护
首先要在旋转前维护该节点的子树的height和size,然后才能根据更新的数据,判断该树是否平衡,然后旋转
void fix(node* &R) { R->h = max(R->rchild->h,R->lchild->h) + 1; R->size = R->rchild->size + R->lchild->size + 1; }
操作2:旋转化操作
插入和删除的时候用同样的旋转维护该树
void rightsinglerotate(node* &R)//LL型旋转,单旋一次 { node * lc = R->lchild; R->lchild = lc->rchild; fix(R); lc->rchild = R; R = lc; fix(R); } void leftsinglerotate(node* &R)//RR型旋转,单选一次 { node * rc = R->rchild; R->rchild = rc->lchild; fix(R); rc->lchild = R; R = rc; fix(R); } void leftdoublerotate(node* &R)//RL型旋转,双旋 { rightsinglerotate(R->rchild); leftsinglerotate(R); } void rightdoublerotate(node* &R)//LR型旋转,双旋 { leftsinglerotate(R->lchild); rightsinglerotate(R); } void maintain(node* &R) { if(R->lchild != MYNULL) { if(R->lchild->lchild->h == R->rchild->h + 1) rightsinglerotate(R); else if(R->lchild->rchild->h == R->rchild->h + 1) rightdoublerotate(R); } if(R->rchild != MYNULL) { if(R->rchild->rchild->h == R->lchild->h + 1) leftsinglerotate(R); else if(R->rchild->lchild->h == R->lchild->h + 1) leftdoublerotate(R); } }
操作3:求第K小的操作,也就是size域的用途
int findK(node* &R,int k) { if(k == R->lchild->size + 1) return R->value; else if(k <= R->lchild->size) return findK(R->lchild,k); else if(k > R->size - R->rchild->size) return findK(R->rchild,k + R->rchild->size - R->size); }
操作4:erase函数,要完成该题的统计功能,看erase了多少次
void erase(node* &R,T value) { if(R == MYNULL) return; if(R->value == value) { if(R->rchild == MYNULL) { node * tmp = R; R = tmp->lchild; } else { node *tmp = R->rchild; while(tmp->lchild != MYNULL) tmp = tmp->lchild; R->value = tmp->value; erase(R->rchild,tmp->value); fix(R); } return; } else if(value < R->value) erase(R->lchild,value); else if(value < R->value) erase(R->rchild,value); fix(R); maintain(R); }
最后在调整树使其不失衡。
有了这些操作就可以轻松的完成题目的要求了,
完整的代码如下
/* * ===================================================================================== * * Filename: AVLtree.cpp * * Description: AVLtree with template * * Version: 1.0 * Created: 2010年12月27日 09时45分44秒 * Revision: none * Compiler: gcc * * Author: ronaflx * Company: hit-acm-group * * ===================================================================================== */ #include <iostream> #include <cstring> #include <cstdio> using namespace std; int delta; const int INF = 10000000; template<typename T> class AVL { public: AVL() { pp = pool; TMP = node(0,0,NULL,NULL); MYNULL = &TMP; roof = MYNULL; } void insert(T k) { insert(roof,k); } void erase(T k) { erase(roof,k); } bool empty() { return roof == MYNULL; } int findK(int k) { if(k <= 0) return -INF; return findK(roof,k); } struct node { node *lchild,*rchild; T value; int h,size; node(){} node (int h,int size,node * lchild,node *rchild) { this->size = size; this->h = h; this->lchild = lchild; this->rchild = rchild; } }; node* roof; private: #define max(a,b) ((a) < (b) ? (b) : (a)) static const int N = 1000000; node* MYNULL,TMP; //为了快速方便的求高度而设立的虚空节点 node pool[N],*pp; int findK(node* &R,int k) { if(k == R->lchild->size + 1) return R->value; else if(k <= R->lchild->size) return findK(R->lchild,k); else if(k > R->size - R->rchild->size) return findK(R->rchild,k + R->rchild->size - R->size); } void fix(node* &R) { R->h = max(R->rchild->h,R->lchild->h) + 1; R->size = R->rchild->size + R->lchild->size + 1; } void rightsinglerotate(node* &R)//LL型旋转,单旋一次 { node * lc = R->lchild; R->lchild = lc->rchild; fix(R); lc->rchild = R; R = lc; fix(R); } void leftsinglerotate(node* &R)//RR型旋转,单选一次 { node * rc = R->rchild; R->rchild = rc->lchild; fix(R); rc->lchild = R; R = rc; fix(R); } void leftdoublerotate(node* &R)//RL型旋转,双旋 { rightsinglerotate(R->rchild); leftsinglerotate(R); } void rightdoublerotate(node* &R)//LR型旋转,双旋 { leftsinglerotate(R->lchild); rightsinglerotate(R); } void maintain(node* &R) { if(R->lchild != MYNULL) { if(R->lchild->lchild->h == R->rchild->h + 1) rightsinglerotate(R); else if(R->lchild->rchild->h == R->rchild->h + 1) rightdoublerotate(R); } if(R->rchild != MYNULL) { if(R->rchild->rchild->h == R->lchild->h + 1) leftsinglerotate(R); else if(R->rchild->lchild->h == R->lchild->h + 1) leftdoublerotate(R); } } void insert(node* &R,T value) { if(R == MYNULL) { R = mynew(value); return; } else if(value <= R->value) insert(R->lchild,value); else if(value > R->value) insert(R->rchild,value); fix(R); maintain(R); } void erase(node* &R,T value) { if(R == MYNULL) return; if(R->value == value) { if(R->rchild == MYNULL) { node * tmp = R; R = tmp->lchild; } else { node *tmp = R->rchild; while(tmp->lchild != MYNULL) tmp = tmp->lchild; R->value = tmp->value; erase(R->rchild,tmp->value); fix(R); } return; } else if(value < R->value) erase(R->lchild,value); else if(value < R->value) erase(R->rchild,value); fix(R); maintain(R); } node* mynew(T value) { pp->lchild = pp->rchild = MYNULL; pp->size = pp->h = 1; pp->value = value; return pp++; } #undef max }; AVL<int> avltree; int main() { int n,minn; char cmd; int f,cnt = 0; while(scanf("%d %d",&n,&minn) == 2) { delta = 0; cnt = 0; while(!avltree.empty()) { avltree.erase(avltree.roof->value); } for(int i = 0;i < n;i++) { scanf(" %c %d",&cmd,&f); if(cmd == 'I') { if(f < minn) continue; avltree.insert(f - delta); } else if(cmd == 'A') delta += f; else if(cmd == 'F') { int tmp = avltree.findK(avltree.roof->size - f + 1); if(tmp == -INF) printf("-1\n"); else printf("%d\n",tmp + delta); } else if(cmd == 'S') { delta -= f; while(!avltree.empty()) { int tmp = avltree.findK(1); tmp += delta; if(tmp >= minn) break; else { cnt++; avltree.erase(tmp - delta); } } } } printf("%d\n",cnt); } return 0; }