线段树的高级用法
1. 动态开点及标记永久化
2. 线段树的分裂和合并
3. 李超线段树
4. zkw线段树
5. 树套树
6. 线段树分治
7. 猫树
7.1 引入
对于某一些特殊的题目,我们不需要进行修改操作,我们是否可以对线段树进行一些处理,以此来加速它的查询时间。
7.2 猫树
下面以区间最值为例。
考虑一个询问
否则,考虑
7.3 实现
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5, LOG = 20;
int n, m, len = 2;
int a[N + 5];
int s[LOG + 5][(N << 2) + 5], pos[(N << 2) + 5], lg[(N << 2) + 5];
int lc(const int &p) { return p << 1; }
int rc(const int &p) { return p << 1 | 1; }
void build(int p, int l, int r, int dep) {
if (l == r)
return pos[l] = p, void();
int mid = (l + r) >> 1;
build(lc(p), l, mid, dep + 1), build(rc(p), mid + 1, r, dep + 1);
s[dep][mid] = a[mid];
for (int i = mid - 1; i >= l; i--)
s[dep][i] = max(s[dep][i + 1], a[i]);
s[dep][mid + 1] = a[mid + 1];
for (int i = mid + 2; i <= r; i++)
s[dep][i] = max(s[dep][i - 1], a[i]);
}
void init() {
while (len < n)
len <<= 1;
for (int i = 2; i <= (len << 1); i++)
lg[i] = lg[i >> 1] + 1;
build(1, 1, len, 1);
}
int query(int l, int r) {
if (l == r)
return a[l];
int d = lg[pos[l]] - lg[pos[l] ^ pos[r]];
return max(s[d][l], s[d][r]);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
init();
while (m--) {
int l, r;
cin >> l >> r;
cout << query(l, r) << '\n';
}
return 0;
}
7.4 例题
本文来自博客园,作者:zhou_ziyi,转载请注明原文链接:https://www.cnblogs.com/zhouziyi/p/Segment_Tree.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具