El pueblo unido jamas serà vencido!

[来骗来偷袭] std::vector 实现的平衡树

前言

有些题跑得飞快,就比较离谱。

实现

std::vectorinserterase 常数非常玄学,复杂度是 \(\mathcal{O}(n)\) 的但是跑得飞快,利用这个性质我们维护一个有序的数组,然后其他操作都可以靠二分解决。

  1. 插入 : std::lower_bound 找到插入位置,保持原数组有序
  2. 删除 : std::lower_bound 找到待删除元素迭代器然后 erase
  3. 排名 : std::lower_bound 求小于这个数有丢失数然后加一
  4. 第 k 大 :数组有序,为下标 k - 1 位置的元素。
  5. 前驱 : std::lower_bound 得到的迭代器向前移动一位
  6. 后继 : 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;
}
posted @ 2022-02-23 16:13  AstatineAi  阅读(176)  评论(0编辑  收藏  举报