[来骗来偷袭] std::vector 实现的平衡树
前言
有些题跑得飞快,就比较离谱。
实现
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
:
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;
}
作者:AstatineAi
本文为 作者 AstatineAi 的原创,遵循CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接及本声明。