[來騙來偷襲] std::vector 實現的平衡樹
阿新 • • 發佈:2022-02-23
前言
有些題跑得飛快,就比較離譜。
實現
std::vector
的 insert
和 erase
常數非常玄學,複雜度是 \(\mathcal{O}(n)\) 的但是跑得飛快,利用這個性質我們維護一個有序的陣列,然後其他操作都可以靠二分解決。
- 插入 :
std::lower_bound
找到插入位置,保持原陣列有序 - 刪除 :
std::lower_bound
找到待刪除元素迭代器然後erase
- 排名 :
std::lower_bound
求小於這個數有丟失數然後加一 - 第 k 大 :陣列有序,為下標
k - 1
位置的元素。 - 前驅 :
std::lower_bound
得到的迭代器向前移動一位 - 後繼 :
std::upper_bound
程式碼
struct BST { std::vector<int> V; inline void ins(int x) { V.insert(std::lower_bound(V.begin(),V.end(),x),x); } inline void del(int x) { V.erase(std::lower_bound(V.begin(),V.end(),x)); } inline int rnk(int x) { return std::lower_bound(V.begin(),V.end(),x) - V.begin() + 1; } inline int kth(int x) { return V.at(x - 1); } inline int pre(int x) { auto it = std::lower_bound(V.begin(),V.end(),x); return it == V.begin() ? -INF : *--it; } inline int suc(int x) { auto it = std::upper_bound(V.begin(),V.end(),x); return it == V.end() ? INF : *it; } };
當然在 P3369 被 FHQ Treap,WBLT,替罪羊等平衡樹吊打,而資料加強版都過不去,但是這不妨礙這個玩意飛快。
線段樹套 vector
:
作者:AstatineAi 出處:https://www.cnblogs.com/AstatineAi/p/use-vector-as-a-BST.html 本文為 作者 AstatineAi 的原創,遵循CC BY-NC-SA 4.0 版權協議,轉載請附上原文出處連結及本宣告。struct BST { std::vector<int> V; inline void ins(int x) { V.insert(std::lower_bound(V.begin(),V.end(),x),x); } inline void del(int x) { V.erase(std::lower_bound(V.begin(),V.end(),x)); } inline int rnk(int x) { return std::lower_bound(V.begin(),V.end(),x) - V.begin() + 1; } inline int kth(int x) { return V.at(x - 1); } inline int pre(int x) { auto it = std::lower_bound(V.begin(),V.end(),x); return it == V.begin() ? -INF : *--it; } inline int suc(int x) { auto it = std::upper_bound(V.begin(),V.end(),x); return it == V.end() ? INF : *it; } }T[N << 2]; int n; int a[N]; void build(int p,int pl,int pr) { if(pl == pr) { T[p].ins(a[pl]); return ; } rep(i,pl,pr) T[p].ins(a[i]); int mid = (pl + pr) >> 1; build(p << 1,pl,mid); build(p << 1 | 1,mid + 1,pr); } void modify(int p,int pl,int pr,int pos,int v) { if(pl == pr) { T[p].del(a[pos]),T[p].ins(v); return ; } T[p].del(a[pos]),T[p].ins(v); int mid = (pl + pr) >> 1; if(pos <= mid) modify(p << 1,pl,mid,pos,v); else modify(p << 1 | 1,mid + 1,pr,pos,v); } int rnk(int p,int pl,int pr,int l,int r,int x) { if(l <= pl && pr <= r) return T[p].rnk(x) - 1; int rk = 0,mid = (pl + pr) >> 1; if(l <= mid) rk += rnk(p << 1,pl,mid,l,r,x); if(r > mid) rk += rnk(p << 1 | 1,mid + 1,pr,l,r,x); return rk; } int kth(int ql,int qr,int k) { int l = 0,r = 1e8,res = 0; while(l <= r) { int mid = (l + r) >> 1; if(rnk(1,1,n,ql,qr,mid) + 1 <= k) res = mid,l = mid + 1; else r = mid - 1; } return res; } int pre(int p,int pl,int pr,int l,int r,int x) { if(l <= pl && pr <= r) return T[p].pre(x); int mid = (pl + pr) >> 1,res = -INF; if(l <= mid) res = std::max(res,pre(p << 1,pl,mid,l,r,x)); if(r > mid) res = std::max(res,pre(p << 1 | 1,mid + 1,pr,l,r,x)); return res; } int suc(int p,int pl,int pr,int l,int r,int x) { if(l <= pl && pr <= r) return T[p].suc(x); int mid = (pl + pr) >> 1,res = INF; if(l <= mid) res = std::min(res,suc(p << 1,pl,mid,l,r,x)); if(r > mid) res = std::min(res,suc(p << 1 | 1,mid + 1,pr,l,r,x)); return res; }