划分树
划分树
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));
}
}

浙公网安备 33010602011771号