替罪羊树
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const double alpha = 0.7;
struct Node
{
int l, r, val, size, cnt;
bool deleted;
} tr[MAXN];
int idx, root;
bool isbad(int u)
{
return tr[tr[u].l].cnt > alpha * tr[u].cnt + 5 || // 左子树失衡检测
tr[tr[u].r].cnt > alpha * tr[u].cnt + 5; // 右子树失衡检测
}
void maintain(int u)
{
tr[u].size = !tr[u].deleted + tr[tr[u].l].size + tr[tr[u].r].size; // 更新有效节点数(排除已删除)
tr[u].cnt = 1 + tr[tr[u].l].cnt + tr[tr[u].r].cnt; // 更新总节点数(包含删除节点)
}
void dfs(int u, vector<int> &v)
{
if (!u)
return; // 空节点直接返回
dfs(tr[u].l, v); // 递归遍历左子树
if (!tr[u].deleted)
v.push_back(u); // 收集未删除的有效节点
dfs(tr[u].r, v); // 递归遍历右子树
}
int build(vector<int> &v, int l, int r)
{
if (l >= r)
return 0; // 基准条件:空区间返回空指针
int mid = (l + r) >> 1; // 取中间元素作为当前根节点
int u = v[mid]; // 获取预存节点索引
tr[u].l = build(v, l, mid); // 递归构建左子树(处理左半区间 [l, mid))
tr[u].r = build(v, mid + 1, r); // 递归构建右子树(处理右半区间 [mid+1, r))
maintain(u); // 维护节点统计信息(size/cnt)
return u; // 返回当前构建的子树根节点
}
void rebuild(int &u)
{
vector<int> v; // 存储有效节点索引
dfs(u, v); // 中序遍历收集未删除节点
u = build(v, 0, v.size()); // 重构平衡树并更新根节点
}
void insert(int x, int &u)
{
if (!u) // 当前为空节点,创建新节点
{
u = ++idx;
tr[u] = {0, 0, x, 1, 1, false}; // 初始化节点属性
return;
}
tr[u].size++; // 更新有效节点数
tr[u].cnt++; // 更新总节点数(含删除节点)
// 递归插入子树
if (x >= tr[u].val)
insert(x, tr[u].r); // 插入右子树
else
insert(x, tr[u].l); // 插入左子树
if (isbad(u)) // 检查平衡性
rebuild(u); // 触发重构
}
int get_rank(int u, int x)
{
int ans = 1; // 初始化排名(从1开始计数)
while (u)
{
if (tr[u].val >= x)
u = tr[u].l; // 目标在左子树(性质)
else
{
// 累加左子树有效节点数 + 当前节点是否有效
ans += tr[tr[u].l].size + !tr[u].deleted;
u = tr[u].r; // 继续搜索右子树
}
}
return ans; // 返回最终排名
}
int kth(int u, int x)
{
while (u)
{
// 命中条件:当前节点有效,且左子树有效节点数+1等于目标排名
if (!tr[u].deleted && tr[tr[u].l].size + 1 == x)
return tr[u].val;
// 左子树足够大时搜索左子树
if (tr[tr[u].l].size >= x)
u = tr[u].l;
else
{
// 调整目标排名:扣除左子树和当前节点有效值
x -= tr[tr[u].l].size + !tr[u].deleted;
u = tr[u].r; // 转向右子树搜索剩余排名
}
}
return -1; // 未找到有效结果
}
void erase(int u, int rk)
{
// 找到目标节点时进行惰性删除
if (!tr[u].deleted && rk == tr[tr[u].l].size + 1)
{
tr[u].deleted = 1; // 标记为已删除
tr[u].size--; // 更新有效节点数
return;
}
// 路径更新:当前子树有效节点数减1
tr[u].size--;
// 递归查找删除位置
if (rk <= tr[tr[u].l].size + !tr[u].deleted)
erase(tr[u].l, rk); // 目标在左子树
else
// 调整目标排名后搜索右子树
erase(tr[u].r, rk - tr[tr[u].l].size - !tr[u].deleted);
}
本文来自博客园,作者:流氓兔LMT,转载请注明原文链接:https://www.cnblogs.com/-include-lmt/p/18737299

浙公网安备 33010602011771号