1. 程式人生 > 其它 >[來騙來偷襲] std::vector 實現的平衡樹

[來騙來偷襲] 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;
}
作者:AstatineAi 出處:https://www.cnblogs.com/AstatineAi/p/use-vector-as-a-BST.html 本文為 作者 AstatineAi 的原創,遵循CC BY-NC-SA 4.0 版權協議,轉載請附上原文出處連結及本宣告。