权值线段树
权值线段树
1、一种可以处理整个数组的第 \(k\) 大数或第 \(k\) 小数的算法,依名可知,该线段树是由数值来建线段树的,如果对于权值为 \(1e9\) 这样的数据,我们也可以通过离散化的方式进行值域压缩,从而缩小到 \(2e5\) 的样子,和普通线段树一样,可以通过懒标记来维护一段区间的修改,每次修改我们都可以添加任意元素。
2、时间复杂度:\(O(nlogn)\),空间复杂度:\(O(nlogn)\)。
3、模版:洛谷P8747。
4、和平衡树差不多的用法,主要可以用来求解查询第 \(k\) 大的数是谁、查询第 \(k\) 小的数是谁、查询 \(x\) 的排名、求 \(x\) 的前驱(小于 \(x\) 的最大数)、求x的后驱(大于 \(x\) 的最小数),平衡树传送门:平衡树。
template<typename T>
struct W_tree{
struct node{
T siz, sum, lzy;
node(T siz = 0, T sum = 0, T lzy = 0) : siz(siz), sum(sum), lzy(lzy) {}
#define ls root << 1
#define rs root << 1 | 1
#define rt(x) tree[x]
};
int mx;
vector<node> tree;
W_tree() {}
W_tree(int mx_) : tree(mx_ << 4) {
mx = mx_;
build(1, 1, mx_);
}
inline void init() {
}
inline node hb(node i, node j) {
node k;
k.siz = i.siz + j.siz;
k.sum = i.sum + j.sum;
return k;
}
inline void push_up(int root, int l, int r) {
rt(root) = hb(rt(ls), rt(rs));
}
inline void push_down(int root, int l, int r) {
int mid = l + r >> 1;
if (rt(root).lzy) {
rt(ls).sum += rt(root).lzy * rt(ls).siz;
rt(rs).sum += rt(root).lzy * rt(rs).siz;
rt(ls).lzy += rt(root).lzy;
rt(rs).lzy += rt(root).lzy;
rt(root).lzy = 0;
}
}
inline void build(int root, int l, int r) {// 建树
int mid = l + r >> 1;
if (l == r) {
rt(root) = node(1, 0, 0);
return;
}
build(ls, l, mid);
build(rs, mid + 1, r);
push_up(root, l, r);
}
inline void ins(int root, int l, int r, int ql, int qr, const T &v) {// 插入或删除
if (r < ql || l > qr) {
return;
}
if (l >= ql && r <= qr) {
rt(root).sum += v * rt(root).siz;
rt(root).lzy += v;
return;
}
push_down(root, l, r);
int mid = l + r >> 1;
ins(ls, l, mid, ql, qr, v);
ins(rs, mid + 1, r, ql, qr, v);
push_up(root, l, r);
}
inline int query_kth_max(int root, int l, int r, T k) {// 查询第k大的数是谁
int mid = l + r >> 1;
if (l == r) {
return l;
}
push_down(root, l, r);
T rg = rt(rs).sum;
if (k <= rg) {
return query_kth_max(rs, mid + 1, r, k);
} else {
return query_kth_max(ls, l, mid, k - rg);
}
}
inline int query_kth_min(int root, int l, int r, T k) {// 查询第k小的数是谁
int mid = l + r >> 1;
if (l == r) {
return l;
}
push_down(root, l, r);
T lf = rt(ls).sum;
if (k <= lf) {
return query_kth_min(ls, l, mid, k);
} else {
return query_kth_min(rs, mid + 1, r, k - lf);
}
}
inline T rtk(int root, int l, int r, int ql, int qr) {// 查询x的排名
int mid = l + r >> 1;
if (r < ql || l > qr) {
return 0;
}
if (l >= ql && r <= qr) {
return rt(root).sum;
}
push_down(root, l, r);
T sum{};
sum += rtk(ls, l, mid, ql, qr);
sum += rtk(rs, mid + 1, r, ql, qr);
return sum;
}
inline int pre(int x) {// 求x的前驱(小于x的最大数)
T sum = rtk(1, 1, mx, 1, x);
return query_kth_min(1, 1, mx, sum);
}
inline int nxt(int x) {// 求x的后驱(大于x的最小数)
T sum = rtk(1, 1, mx, x, mx);
return query_kth_max(1, 1, mx, sum);
}
};
void solve() {
int m;
read(m);
int cnt = 0;
set<i64> s;
map<int, int> mp, mp2;
vector<PI> a(m);
for (int i = 0; i < m; i++) {
read(a[i].first, a[i].second);
s.insert(a[i].second);
s.insert(a[i].second - 1);
s.insert(a[i].second + 1);
}
for (auto p : s) {
mp[p] = ++cnt;
mp2[cnt] = p;
}
W_tree<i64> tr(cnt);
for (auto [op, x] : a) {
if (op == 1) {
tr.ins(1, 1, cnt, mp[x], mp[x], 1);
} else if (op == 2) {
tr.ins(1, 1, cnt, mp[x], mp[x], -1);
} else if (op == 3) {
i64 sum = tr.rtk(1, 1, cnt, 1, mp[x - 1]) + 1;
printf("%lld\n", sum);
} else if (op == 4) {
int sum = tr.query_kth_min(1, 1, cnt, x);
printf("%d\n", mp2[sum]);
} else if (op == 5) {
int sum = tr.pre(mp[x - 1]);
printf("%d\n", mp2[sum]);
} else if (op == 6) {
int sum = tr.nxt(mp[x + 1]);
printf("%d\n", mp2[sum]);
}
}
}

浙公网安备 33010602011771号