暂存一下线段树模板
template <class Info> // 模板类,Info 是一个模板参数,表示线段树节点存储的信息类型
struct SegmentTree {
int n; // 表示线段树中存储的元素个数
vector<Info> info; // 用于存储线段树节点的数组,类型为 Info
SegmentTree() : n(0) {} // 默认构造函数,初始化 n 为 0
// 传入 n_ 表示元素个数,v_ 表示初始化的默认值
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
// 模板构造函数:传入一个向量,用于初始化线段树
template <class T>
SegmentTree(vector<T> init_) {
init(init_);
}
// 初始化函数:传入元素个数和默认值
void init(int n_, Info v_ = Info()) {
init(vector(n_, v_)); // 用一个大小为 n_ 的向量初始化,元素值为 v_
}
// 模板初始化函数:传入一个向量,用于初始化线段树
template <class T>
void init(vector<T> init_) {
n = init_.size(); // 记录元素个数
// 初始化 info 数组的大小,4 << __lg(n) 是 2 的 log(n) 次方乘以 4
info.assign(4 << __lg(n), Info());
auto build = [&](auto self, int p, int l, int r) -> void {
if (r - l == 1) { // 如果区间长度为 1,说明是叶节点
info[p] = init_[l]; // 将叶节点赋值为初始化向量的对应值
return;
}
int m = (l + r) / 2; // 计算区间中点
self(self, 2 * p, l, m); // 递归构建左子树
self(self, 2 * p + 1, m, r); // 递归构建右子树
pushup(p); // 更新当前节点的值为其两个子节点的合并值
};
build(build, 1, 0, n); // 调用 Lambda 函数,从根节点开始构建线段树
}
void pushup(int p) {
info[p] = info[2 * p] + info[2 * p + 1];
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) { // 如果区间长度为 1,说明是叶节点
info[p] = v; // 直接修改
return;
}
int m = (l + r) / 2;
if (x < m) {
modify(2 * p, l, m, x, v); // 递归修改左子树
} else {
modify(2 * p + 1, m, r, x, v); // 递归修改右子树
}
pushup(p); // 更新当前节点的值为其两个子节点的合并值
}
// 对外的修改接口,只需传入修改位置和新值
void modify(int p, const Info &v) {
modify(1, 0, n, p, v); // 从根节点开始递归修改
}
// 区间查询函数:递归查询区间 [x, y) 的信息
Info rangeQuery(int p, int l, int r, int x, int y) {
if (l >= y || r <= x) { // 如果查询区间与当前区间无交集
return Info(); // 返回默认的 Info 对象
}
if (l >= x && r <= y) { // 如果当前区间完全包含在查询区间内
return info[p]; // 返回当前节点的值
}
int m = (l + r) / 2; // 计算区间中点
// 递归查询左子树和右子树,并合并结果
return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
}
// 对外的区间查询接口,传入区间 [l, r)
Info rangeQuery(int l, int r) {
return rangeQuery(1, 0, n, l, r); // 从根节点开始查询
}
// 查找区间内第一个满足条件的元素
template <class F>
int findFirst(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y || r <= x) { // 如果查询区间与当前区间无交集
return -1; // 返回 -1 表示未找到
}
if (l >= x && r <= y && !pred(info[p])) { // 如果当前区间完全包含在查询区间内且不满足条件
return -1; // 返回 -1 表示未找到
}
if (r - l == 1) { // 如果区间长度为 1,说明是叶节点
return l; // 返回叶节点的位置
}
int m = (l + r) / 2; // 计算区间中点
int res = findFirst(2 * p, l, m, x, y, pred); // 递归查找左子树
if (res == -1) { // 如果左子树未找到,继续查找右子树
res = findFirst(2 * p + 1, m, r, x, y, pred);
}
return res; // 返回结果
}
// 对外的查找接口,查找区间 [l, r) 内第一个满足条件的元素
template <class F>
int findFirst(int l, int r, F &&pred) {
return findFirst(1, 0, n, l, r, pred); // 从根节点开始查找
}
// 查找区间内最后一个满足条件的元素
template <class F>
int findLast(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y || r <= x) { // 如果查询区间与当前区间无交集
return -1; // 返回 -1 表示未找到
}
if (l >= x && r <= y && !pred(info[p])) { // 如果当前区间完全包含在查询区间内且不满足条件
return -1; // 返回 -1 表示未找到
}
if (r - l == 1) { // 如果区间长度为 1,说明是叶节点
return l; // 返回叶节点的位置
}
int m = (l + r) / 2;
int res = findLast(2 * p + 1, m, r, x, y, pred); // 递归查找右子树
if (res == -1) { // 如果右子树未找到,继续查找左子树
res = findLast(2 * p, l, m, x, y, pred);
}
return res; // 返回结果
}
// 对外的查找接口,查找区间 [l, r) 内最后一个满足条件的元素
template <class F>
int findLast(int l, int r, F &&pred) {
return findLast(1, 0, n, l, r, pred); // 从根节点开始查找
}
};
__EOF__

本文作者:爱飞鱼
本文链接:https://www.cnblogs.com/mathiter/p/18514820.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/mathiter/p/18514820.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话