P6136 【模板】普通平衡樹(資料加強版) 非旋轉treap演算法指標版
阿新 • • 發佈:2022-03-27
//非旋轉的Treap樹 #include<bits/stdc++.h> using namespace std; const int INF=0x7fffffff; struct Node *nil; // 自定義的空指標,防止翻車(RE) struct Node { Node *ch[2]; // 結點的左右孩子。為什麼不分開寫成lc,rc呢?往後就知道了 int v, s, c; // v表示該結點的值,s表示以該結點為根的子樹大小,c表示權值v的結點數量(合併了相同權值的結點),即v的副本數量 int r; // Treap專有的隨機數,是大根堆的關鍵字 void maintain() { // 維護當前結點的資訊 s = ch[0]->s + ch[1]->s + c; } Node(int v) : v(v), c(1), s(1), r(rand()) { ch[0] = ch[1] = nil; } // 新建結點 } *root; void init() { srand(0); // 隨機數初始化 nil = new Node(0); // 空指標初始化 root = nil->ch[0] = nil->ch[1] = nil; // 左右孩子指向自身 nil->s = nil->c = 0; // 防止空指標影響後面的操作 } void split(Node *o, int v, Node* &l, Node* &r) { if (o == nil) { l = r = nil; return; } // 到了空結點兩邊附上空後結束 if (o->v < v) { l = o; split(o->ch[1], v, l->ch[1], r); l->maintain(); } // 第一種情況。注意分裂後要及時維護資訊 else { r = o; split(o->ch[0], v, l, r->ch[0]); r->maintain(); } // 第二種情況。同上 } Node* merge(Node *a, Node *b) { if (a == nil) return b; // 如果a空返回b if (b == nil) return a; // 如果b空返回a if (a->r > b->r) { a->ch[1] = merge(a->ch[1], b); a->maintain(); return a; } // 比較兩者的隨機關鍵字,大的先合併 else { b->ch[0] = merge(a, b->ch[0]); b->maintain(); return b; } } void insert(Node* &rt, int v) { Node *l, *r; split(rt, v, l, r); rt = merge(merge(l, new Node(v)), r); } void remove(Node* &rt, int v) { Node *l, *mid, *r; split(rt, v, l, r); split(r, v+1, mid, r); rt = merge(merge(l, merge(mid->ch[0], mid->ch[1])), r); delete mid; } //v的排名 int get_rank(Node* o, int v) { /* 10 /\ 4 \ 10 /\ 7 /\ .. 10 有錯 if (v < o->v) return get_rank(o->ch[0], v); // v在左子樹中 if (o->ch[0]&&o->ch[0]->v==v) return get_rank(o->ch[0],v); if (o->v== v) return o->ch[0]->s + 1; // 找到v return get_rank(o->ch[1], v) + o->ch[0]->s + o->c; // v在右子樹中,此時要將左子樹中的所有元素以及根的元素數統計起來 */ /* int ans=0; while(o!=nil) { if (o->v>=v) { o=o->ch[0]; } else { ans+=o->ch[0]->s+1; o=o->ch[1]; } } return ans+1; */ if (o==nil) return 1; if (o->v>=v) return get_rank(o->ch[0],v); else return o->ch[0]->s+1+get_rank(o->ch[1],v); } //第k小數 int get_val(Node* o, int k) { if (k <= o->ch[0]->s) return get_val(o->ch[0], k); // 排名為k的數在左子樹中 else if (k == o->ch[0]->s + o->c) return o->v; // 為o else return get_val(o->ch[1], k - o->ch[0]->s - o->c); // 在右子樹中 } int get_pre(Node *o, int v) { // 查前驅 if (o == nil) return -INF; // 找到空結點返回無窮小目的是不干擾其它解 if (o->v >= v) return get_pre(o->ch[0], v); // v大於當前結點o的值,向左走找小一點的值 return max(o->v, get_pre(o->ch[1], v)); // 否則向右走找更大的值並與當前值比較 /* 有點慢 if (o == nil) return -INF; // 找到空結點返回無窮小目的是不干擾其它解 return get_val(o,get_rank(o,v)-1); */ } int get_next(Node *o, int v) { // 查後繼,與上面完全相反 /* if (o == nil) return INF; if (o->v <= v) return get_next(o->ch[1], v); return min(o->v, get_next(o->ch[0], v)); */ return get_val(o,get_rank(o,v+1));//有點慢 } int main() { int n,m,op,x,last=0,ans=0; init(); scanf("%d %d",&n,&m); while(n--) { scanf("%d",&x); insert(root,x); } while(m--) { scanf("%d %d",&op,&x); x=last^x; if (op==1) insert(root,x); else if(op==2) remove(root,x); else if(op==3) { last=get_rank(root,x); ans^=last; } else if(op==4) { last=get_val(root,x); ans^=last; } else if(op==5) { last=get_pre(root,x); ans^=last; } else if(op==6) { last=get_next(root,x); ans^=last; } } cout<<ans<<endl; }