https://zhuanlan.zhihu.com/p/21263304
里面有关于替罪羊树的详细介绍,这里就不再赘述。
#include <vector> #include <cstdio> #include <iostream> using namespace std; namespace Scapegoat_Tree { #define MAXN (100000 + 10) const double alpha = 0.75; struct Node { Node *ch[2]; int key, sz, cover; bool exist; void pushup() { sz = ch[0]->sz + ch[1]->sz + (int)exist; cover = ch[0]->cover + ch[1]->cover + 1; } bool isbad() { return (ch[0]->cover > cover * alpha + 5)|| (ch[1]->cover > cover * alpha + 5); } }; struct STree { protected: Node mem_poor[MAXN]; Node *tail, *root, *null; Node *bc[MAXN]; int bc_top; Node * Newnode(int key) { Node *p = bc_top ? bc[--bc_top] : tail++; p->ch[0] = p->ch[1] = null; p->sz = p->cover = 1; p->exist = true; p->key = key; return p; } void Travel(Node *p, vector<Node *> &v) { if(p == null) return; Travel(p->ch[0], v); if(p->exist) v.push_back(p); else bc[bc_top++] = p; Travel(p->ch[1], v); } Node* Divide(vector<Node *> &v, int l, int r) { if(l >= r) return null; int mid = (l+r)>>1; Node *p = v[mid]; p->ch[0] = Divide(v, l, mid); p->ch[1] = Divide(v, mid+1, r); p->pushup(); return p; } void Rebuild(Node *& p) { static vector<Node *>v; v.clear(); Travel(p, v); p = Divide(v, 0, v.size()); } Node ** Insert(Node *&p, int val) { if(p == null) { p = Newnode(val); return &null; } else { p->sz++; p->cover++; Node **res = Insert(p->ch[val >= p->key], val); if(p->isbad()) res = &p; return res; } } void Erase(Node *p, int id) { p->sz--; int offset = p->ch[0]->sz + p->exist; if(p->exist && id == offset) { p->exist = false; return; } else { if(id <= offset) Erase(p->ch[0], id); else Erase(p->ch[1], id - offset); } } public: void init() { tail = mem_poor; null = tail++; null->ch[0] = null->ch[1] = null; null->cover = null->sz = null->key = 0; root = null; bc_top = 0; } void Insert(int val) { Node **p = Insert(root, val); if(*p != null) Rebuild(*p); } int Rank(int val) { Node *now = root; int ans = 1; while(now != null) { if(now->key >= val) now = now->ch[0]; else { ans += now->ch[0]->sz + now->exist; now = now->ch[1]; } } return ans; } int Kth(int k) { Node *now = root; while(now != null) { if(now->ch[0]->sz + 1 == k && now->exist) return now->key; else if(now->ch[0]->sz >= k) now = now->ch[0]; else k -= now->ch[0]->sz + now->exist, now = now->ch[1]; } return 0; } void Erase(int k) { Erase(root, Rank(k)); if(root->sz < alpha*root->cover) Rebuild(root); } void Erase_kth(int k) { Erase(root, k); if(root->sz < alpha * root->cover) Rebuild(root); } }; #undef MAXN } using namespace Scapegoat_Tree; STree root; int main() { int T, x, y; cin>>T; root.init(); while(T--) { scanf("%d %d", &x, &y); switch(x) { case 1: root.Insert(y); break; case 2: root.Erase(y); break; case 3: printf("%d ", root.Rank(y)); break; case 4: printf("%d ", root.Kth(y)); break; case 5: printf("%d ", root.Kth(root.Rank(y)-1)); break; case 6: printf("%d ", root.Kth(root.Rank(y+1))); break; } } }