划分树

划分树

1、和主席树差不多的用法,只不过常数比主席树小。

2、可用于求解静态区间第 \(k\) 小问题。

3、时间复杂度:\(O(nlogn)\),空间复杂度:\(o(nlogn)\),所以划分树是一个非常优的算法。

4、模版:洛谷P3834

template<typename T>
struct HF_tree{
	int n;
	vector<T> a;
	vector<vector<T>> tree;
    vector<vector<int>> l_siz;
	
    HF_tree() {}
	HF_tree(int n_) : a(n_ + 1), tree(21, vector<T>(n_ + 1)), l_siz(21, vector<int>(n_ + 1)) {
        n = n_;
    }
	
	inline void init() {
    }
	
	inline void build(int l, int r, int deep) {
		if (l == r) return;
		int mid = l + r >> 1;
		int sum = mid - l + 1;
		for (int i = l; i <= r; i++) {
			if (tree[deep][i] < a[mid]) sum--;
		}
		
		int ls = l, rs = mid + 1;
		
		for (int i = l; i <= r; i++) {
			bool flag = 0;
			if (tree[deep][i] < a[mid] || (tree[deep][i] == a[mid] && sum > 0)) {
				flag = 1;
				tree[deep + 1][ls++] = tree[deep][i];
				if (tree[deep][i] == a[mid]) sum--;
			} else {
				tree[deep + 1][rs++] = tree[deep][i];
			}
			
			l_siz[deep][i] += (i == l ? 0 : l_siz[deep][i - 1]) + flag;
		}
		
		build(l, mid, deep + 1);
		build(mid + 1, r, deep + 1);
	}
	
	inline T query(int l, int r, int ql, int qr, int k, int deep) {
		if (l == r) return tree[deep][l];
		int mid = l + r >> 1;
		int cnt = l_siz[deep][qr] - (ql == l ? 0 : l_siz[deep][ql - 1]);
		
		if (cnt >= k) {
			int newl = l + (ql == l ? 0 : l_siz[deep][ql - 1]);
			int newr = newl + cnt - 1;
			return query(l, mid, newl, newr, k, deep + 1);
		} else {
			int newl = mid + 1 + (ql == l ? 0 : ql - l - l_siz[deep][ql - 1]);
			int newr = newl + qr - ql - cnt;
			return query(mid + 1, r, newl, newr, k - cnt, deep + 1);
		}
	}
};

void solve() {
	int n, m;
	read(n, m);
	HF_tree<int> tr(n);
	for (int i = 1; i <= n; i++) {
		read(tr.a[i]);
		tr.tree[1][i] = tr.a[i];
	}
	sort(tr.a.begin() + 1, tr.a.end());
	tr.build(1, n, 1);
	
	while (m--) {
		int l, r, k;
		read(l, r, k);
		printf("%d\n", tr.query(1, n, l, r, k, 1));
	}
}
posted @ 2024-08-15 02:40  grape_king  阅读(15)  评论(0)    收藏  举报