數據結構復習1
阿新 • • 發佈:2018-07-20
ret char for con const ota pac 沒有 getch
數據結構復習1
主席樹
細節:
- x和y是節點編號,所以是root[i]不是i
- 每次復制原來的節點,再新建
線段樹
標記
多個標記考慮優先級
滿足區間加法就可以用線段樹
平衡樹
Treap
滿足平衡樹的性質,同時隨機附加域維護一個小根堆
- rturn,左兒子成為根 c=t[x].l t[x].l=t[c].r t[c].r=x
- lturn,右兒子成為根
- 插入
- !x 新建節點
- 判斷向哪走,遞歸結束時維護堆性質
- 刪除
- !x 返回
- 判斷有幾個,1個的話左右兒子誰繼承他。註意先旋轉再刪自己的技巧
- 還不到就走
- rnk, kth, pre, suf
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define lc t[x].l #define rc t[x].r const int N = 1e5+5; inline int read() { int x=0, f=1; char c=getchar(); while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();} return x*f; } struct meow { int x, l, r, v, w, size, rnd; meow() {} meow(int a) {l=r=0; v=a; w=size=1; rnd=rand();} } t[N]; int sz, root; inline void update(int x) { t[x].size = t[lc].size + t[rc].size + t[x].w; } inline void rturn(int &x) { int c = lc; lc = t[c].r; t[c].r = x; t[c].size = t[x].size; update(x); x=c; } inline void lturn(int &x) { int c = rc; rc = t[c].l; t[c].l = x; t[c].size = t[x].size; update(x); x=c; } void insert(int &x, int v) { if(!x) { x = ++sz; t[x] = meow(v); } else { t[x].size++; if(v == t[x].v) t[x].w++; else if(v < t[x].v) { insert(lc, v); if(t[lc].rnd < t[x].rnd) rturn(x); } else { insert(rc, v); if(t[rc].rnd < t[x].rnd) lturn(x); } } } void erase(int &x, int v) { if(!x) return; if(v == t[x].v) { if(t[x].w > 1) t[x].w--, t[x].size--; else if(!lc || !rc) x = lc|rc; else if(t[lc].rnd < t[rc].rnd) rturn(x), erase(x, v); else lturn(x), erase(x, v); } else { t[x].size--; if(v < t[x].v) erase(lc, v); else erase(rc, v); } } int rnk(int x, int v) { if(!x) return 0; if(v == t[x].v) return t[lc].size + 1; else if(v < t[x].v) return rnk(lc, v); else return t[lc].size + t[x].w + rnk(rc, v); } int kth(int x, int k) { if(!x) return 0; if(k <= t[lc].size) return kth(lc, k); else if(k <= t[lc].size + t[x].w) return t[x].v; else return kth(rc, k - t[lc].size - t[x].w); } int ans = 0; void pre(int x, int v) { if(!x) return; if(t[x].v < v) ans = x, pre(rc, v); else pre(lc, v); } void suf(int x, int v) { if(!x) return; if(t[x].v > v) ans = x, suf(lc, v); else suf(rc, v); } int n; int main() { freopen("in", "r", stdin); srand(2333); n = read(); for(int i=1; i<=n; i++) { int c = read(), x = read(); if(c == 1) insert(root, x); else if(c == 2) erase(root, x); else if(c == 3) printf("%d\n", rnk(root, x)); else if(c == 4) printf("%d\n", kth(root, x)); else if(c == 5) pre(root, x), printf("%d\n", t[ans].v); else if(c == 6) suf(root, x), printf("%d\n", t[ans].v); } }
Splay
伸展樹。插入、查詢後將該節點splay到根
- rotate 將x轉到父親的位置 註意fa信息的維護
- splay 將x伸展到父親為tar的位置 共線時先轉父親
- 插入
- !root 新節點是根
- 已存在v
- 不存在v,記錄last信息,找到後處理
- 尋找 將v找到並splay到根
- 刪除
- splay到根
- 多個
- 沒有兒子,一個兒子
- 兩個兒子,找左子樹最大節點,splay到左兒子,右兒子接在左兒子右邊
- rnk, kth, pre, suf
- 區間操作 [l,r] 將l-1對應的節點splay到左子樹,r+1對應的節點splay到柚子樹,r+1的左兒子子樹就是區間[l,r]
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define lc t[x].ch[0] #define rc t[x].ch[1] #define pa t[x].fa const int N = 1e5+5; inline int read() { int x=0, f=1; char c=getchar(); while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();} return x*f; } struct meow { int ch[2], fa, v, w, size; meow() {} meow(int a) {ch[0]=ch[1]=fa=0; v=a; w=size=1;} } t[N]; int sz, root; inline void update(int x) { t[x].size = t[lc].size + t[rc].size + t[x].w; } inline int wh(int x) {return t[pa].ch[1] == x;} inline void rotate(int x) { int f = t[x].fa, g = t[f].fa, c = wh(x); if(g) t[g].ch[wh(f)] = x; t[x].fa = g; t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].fa = f; t[x].ch[c^1] = f; t[f].fa = x; update(f); update(x); } inline void splay(int x, int tar) { for(; pa != tar; rotate(x)) if(t[pa].fa != tar) rotate(wh(x) == wh(pa) ? pa : x); if(!tar) root = x; } void insert(int v) { if(!root) {root = ++sz; t[root] = meow(v); return;} int x = root, last = 0; while(x) { if(v == t[x].v) { t[x].w++; t[x].size++; splay(x, 0); return; } last = x; if(v < t[x].v) x = lc; else x = rc; } x = ++sz; t[x] = meow(v); if(v < t[last].v) t[last].ch[0] = x; else t[last].ch[1] = x; t[x].fa = last; splay(x, 0); } int find(int v) { int x = root; while(x) { if(v == t[x].v) {splay(x, 0); break;} else if(v < t[x].v) x = lc; else x = rc; } return x; } void erase(int v) { int x = find(v); if(t[x].w > 1) t[x].w--, t[x].size--; else if(!lc && !rc) root = 0; else if(!rc) t[lc].fa = 0, root = lc; else if(!lc) t[rc].fa = 0, root = rc; else { int _ = lc; while(t[_].ch[1]) _ = t[_].ch[1]; splay(_, x); t[_].ch[1] = rc; t[rc].fa = _; t[_].fa = 0; root = _; update(root); } } int rnk(int v) { int x = root, lsize = 0; while(x) { if(v == t[x].v) { int ans = lsize + t[lc].size + 1; splay(x, 0); return ans; } else if(v < t[x].v) x = lc; else lsize += t[lc].size + t[x].w, x = rc; } return -1; } int kth(int k) { int x = root; while(x) { if(k <= t[lc].size) x = lc; else if(k <= t[lc].size + t[x].w) return t[x].v; else k -= t[lc].size + t[x].w, x = rc; } return -1; } int pre(int v) { int x = root, ans = 0; while(x) { if(t[x].v < v) ans = x, x = rc; else x = lc; } return ans; } int suf(int v) { int x = root, ans = 0; while(x) { if(t[x].v > v) ans = x, x = lc; else x = rc; } return ans; } int n, ans; int main() { freopen("in", "r", stdin); n = read(); for(int i=1; i<=n; i++) { int c = read(), x = read(); if(c == 1) insert(x); else if(c == 2) erase(x); else if(c == 3) printf("%d\n", rnk(x)); else if(c == 4) printf("%d\n", kth(x)); else if(c == 5) ans = pre(x), printf("%d\n", t[ans].v); else if(c == 6) ans = suf(x), printf("%d\n", t[ans].v); } }
數據結構復習1