线段树的高级用法

1. 动态开点及标记永久化

2. 线段树的分裂和合并

3. 李超线段树

4. zkw线段树

5. 树套树

6. 线段树分治

7. 猫树

7.1 引入

对于某一些特殊的题目,我们不需要进行修改操作,我们是否可以对线段树进行一些处理,以此来加速它的查询时间。

7.2 猫树

下面以区间最值为例。

考虑一个询问 [l,r]。如果 l=r,则我们可以直接得出答案。
否则,考虑 [l,r] 在线段树上定位时,是线段树中的哪个节点同时递归到左右两个儿子,我们假设这个点为 p 中。

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 例题

posted @   zhou_ziyi  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示