• 对于数组应用于区间染色实现为On,而线段树是O(logn)

  • 什么是线段树:对于一个二叉树,每一个节点存储的是一个线段或是一个区间相应的信息。









查询

更新

#pragma once

#include <cassert>
#include <functional> template<typename T>
class SegmentTree {
public:
SegmentTree() noexcept = default; explicit SegmentTree(const T *const arr, const int n, std::function<T(T, T)> func) : data(new T[n]),
tree(new T[4 * n]),
size(n),
function(func) {
for (int i = 0; i < n; ++i) {
data[i] = arr[i];
}
//构建线段树 根索引为0,左边界为0,有边界为 size-1
buildSegmentTree(0, 0, size - 1);
} ~SegmentTree() noexcept {
delete[] data;
data = nullptr;
delete[] tree;
tree = nullptr;
} constexpr int getSize() const noexcept {
return size;
} T get(const int index) const {
assert(index >= 0 && index < size);
return data[index];
} T query(const int queryL, const int queryR) {
assert(queryL >= 0 && queryL < size && queryR >= 0 && queryR < size && queryL <= queryR);
return query(0, 0, size - 1, queryL, queryR);
} void set(const int index, const T &e) {
assert(index >= 0 && index < size);
data[index] = e;
set(0, 0, size - 1, index, e);
} void print() const {
std::cout << "[";
for (int i = 0; i < size * 4; ++i) {
if (tree[i] != NULL) {
std::cout << tree[i];
} else {
std::cout << "0";
}
if (i != size * 4 - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
} private: void set(const int treeIndex, const int l, const int r, const int index, const T &e) {
//都叶子了,一定是它了,更新它
if (l == r) {
tree[treeIndex] = e;
return;
}
int mid = l + (r - l) / 2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
//要找的索引大于中间值,一定在右边
if (index >= mid + 1) {
set(rightTreeIndex, mid + 1, r, index, e);
} else if (index <= mid) { //否则在左边
set(leftTreeIndex, l, mid, index, e);
}
//更新...
tree[treeIndex] = function(tree[leftTreeIndex], tree[rightTreeIndex]);
} //在以treeIndex为根的线段树[l...r]的范围里,搜索区间[queryL,queryR]的值
int query(const int treeIndex, const int l, const int r, const int queryL, const int queryR) {
//如果左右相同就找到了
if (l == queryL && r == queryR) {
return tree[treeIndex];
}
int mid = l + (r - l) / 2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
//如果查找的范围左边界大于中间
if (mid + 1 <= queryL) {
//那么就不用查找左边
return query(rightTreeIndex, mid + 1, r, queryL, queryR);
//如果查找的范围右边小于中间
} else if (mid >= queryR) {
//那么就不用查找右边
return query(leftTreeIndex, l, mid, queryL, queryR);
}
//如果查找的范围占用两个区间
T leftResult = query(leftTreeIndex, l, mid, queryL, mid);
T rightResult = query(rightTreeIndex, mid + 1, r, mid + 1, queryR);
return function(leftResult, rightResult);
} void buildSegmentTree(const int treeIndex, const int left, const int right) {
//如果左右相等就说明递归到底
if (left == right) {
tree[treeIndex] = data[left];
return;
}
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
int mid = left + (right - left) / 2;
//递归左右孩子根为左右孩子索引,左右边界以中间为界
buildSegmentTree(leftTreeIndex, left, mid);
buildSegmentTree(rightTreeIndex, mid + 1, right);
//线段存储信息根据业务写相应的代码,以求和为例,
tree[treeIndex] = function(tree[leftTreeIndex], tree[rightTreeIndex]);
} constexpr int leftChild(const int index) const noexcept {
return index * 2 + 1;
} constexpr int rightChild(const int index) const noexcept {
return index * 2 + 2;
} private:
std::function<T(T, T)> function;
T *tree;
T *data;
int size;
};
#include <iostream>
#include "SegmentTree.h" int main() {
int nums[] = {-2, 0, 3, -5, 2, -1};
SegmentTree<int> *segmentTree = new SegmentTree<int>(nums, sizeof(nums) / sizeof(int), [](int a, int b) -> int {
return a + b;
});
std::cout << segmentTree->query(0,2) << std::endl;
std::cout << segmentTree->query(2,5) << std::endl;
std::cout << segmentTree->query(0,5) << std::endl;
segmentTree->print();
segmentTree->set(0,0);
segmentTree->print();
std::cout << segmentTree->query(0,2) << std::endl;
std::cout << segmentTree->query(2,5) << std::endl;
std::cout << segmentTree->query(0,5) << std::endl; return 0;
}
输出
1
-1
-3
[-3, 1, -4, -2, 3, -3, -1, -2, 0, 0, 0, -5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[-1, 3, -4, 0, 3, -3, -1, 0, 0, 0, 0, -5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3
-1
-1

LeetCode

307. 区域和检索 - 数组可修改

给你一个数组 nums ,请你完成两类查询。

  1. 其中一类查询要求 更新 数组 nums 下标对应的值
  2. 另一类查询要求返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 和 ,其中 left <= right

    实现 NumArray 类:
  • NumArray(int[] nums) 用整数数组 nums 初始化对象
  • void update(int index, int val) 将 nums[index] 的值 更新 为 val
  • int sumRange(int left, int right) 返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 和 (即,nums[left] + nums[left + 1], ..., nums[right])
class NumArray
{
public:
NumArray(vector<int> nums)
{
if (nums.size() > 0)
{
int *data = new int[nums.size()];
for (int i = 0; i < nums.size(); ++i)
{
data[i] = nums[i];
}
segmentTree = new SegmentTree<int>(data, nums.size(), [](int a, int b) -> int
{ return a + b; });
}
} void update(int i, int val)
{
assert(segmentTree != nullptr);
segmentTree->set(i, val);
} int sumRange(int i, int j)
{
assert(segmentTree != nullptr);
return segmentTree->query(i, j);
} private:
template<typename T>
class SegmentTree {
public:
SegmentTree() noexcept = default; explicit SegmentTree(const T *const arr, const int n, std::function<T(T, T)> func) : data(new T[n]),
tree(new T[4 * n]),
size(n),
function(func) {
for (int i = 0; i < n; ++i) {
data[i] = arr[i];
}
//构建线段树 根索引为0,左边界为0,有边界为 size-1
buildSegmentTree(0, 0, size - 1);
} ~SegmentTree() noexcept {
delete[] data;
data = nullptr;
delete[] tree;
tree = nullptr;
} constexpr int getSize() const noexcept {
return size;
} T get(const int index) const {
assert(index >= 0 && index < size);
return data[index];
} T query(const int queryL, const int queryR) {
assert(queryL >= 0 && queryL < size && queryR >= 0 && queryR < size && queryL <= queryR);
return query(0, 0, size - 1, queryL, queryR);
} void set(const int index, const T &e) {
assert(index >= 0 && index < size);
data[index] = e;
set(0, 0, size - 1, index, e);
} void print() const {
std::cout << "[";
for (int i = 0; i < size * 4; ++i) {
if (tree[i] != NULL) {
std::cout << tree[i];
} else {
std::cout << "0";
}
if (i != size * 4 - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
} private: void set(const int treeIndex, const int l, const int r, const int index, const T &e) {
//都叶子了,一定是它了,更新它
if (l == r) {
tree[treeIndex] = e;
return;
}
int mid = l + (r - l) / 2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
//要找的索引大于中间值,一定在右边
if (index >= mid + 1) {
set(rightTreeIndex, mid + 1, r, index, e);
} else if (index <= mid) { //否则在左边
set(leftTreeIndex, l, mid, index, e);
}
//更新...
tree[treeIndex] = function(tree[leftTreeIndex], tree[rightTreeIndex]);
} //在以treeIndex为根的线段树[l...r]的范围里,搜索区间[queryL,queryR]的值
int query(const int treeIndex, const int l, const int r, const int queryL, const int queryR) {
//如果左右相同就找到了
if (l == queryL && r == queryR) {
return tree[treeIndex];
}
int mid = l + (r - l) / 2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
//如果查找的范围左边界大于中间
if (mid + 1 <= queryL) {
//那么就不用查找左边
return query(rightTreeIndex, mid + 1, r, queryL, queryR);
//如果查找的范围右边小于中间
} else if (mid >= queryR) {
//那么就不用查找右边
return query(leftTreeIndex, l, mid, queryL, queryR);
}
//如果查找的范围占用两个区间
T leftResult = query(leftTreeIndex, l, mid, queryL, mid);
T rightResult = query(rightTreeIndex, mid + 1, r, mid + 1, queryR);
return function(leftResult, rightResult);
} void buildSegmentTree(const int treeIndex, const int left, const int right) {
//如果左右相等就说明递归到底
if (left == right) {
tree[treeIndex] = data[left];
return;
}
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
int mid = left + (right - left) / 2;
//递归左右孩子根为左右孩子索引,左右边界以中间为界
buildSegmentTree(leftTreeIndex, left, mid);
buildSegmentTree(rightTreeIndex, mid + 1, right);
//线段存储信息根据业务写相应的代码,以求和为例,
tree[treeIndex] = function(tree[leftTreeIndex], tree[rightTreeIndex]);
} constexpr int leftChild(const int index) const noexcept {
return index * 2 + 1;
} constexpr int rightChild(const int index) const noexcept {
return index * 2 + 2;
} private:
std::function<T(T, T)> function;
T *tree;
T *data;
int size;
};
SegmentTree<int> *segmentTree;
};

线段树(SegmentTree)的更多相关文章

  1. java——线段树 SegmentTree

    应用: 区间染色 区间查询 线段树不是完全二叉树,线段树是平衡二叉树 使用数组来实现线段树:存储空间为4n 以下是使用数组实现的静态线段树: public class SegmentTree<E ...

  2. 模板 - 数据结构 - 线段树/SegmentTree

    区间求加法和: 单点修改的,普通线段树. struct SegmentTree { #define ls (o<<1) #define rs (o<<1|1) static c ...

  3. 【LeetCode】线段树 segment-tree(共9题)+ 树状数组 binary-indexed-tree(共5题)

    第一部分---线段树:https://leetcode.com/tag/segment-tree/ [218]The Skyline Problem [307]Range Sum Query - Mu ...

  4. 线段树(SegmentTree)基础模板

    线段树模板题来源:https://www.lintcode.com/problem/segment-tree-build/description 201. 线段树的构造 /** * Definitio ...

  5. 【hihoCoder】第20周 线段树

    题目: 输入 每个测试点(输入文件)有且仅有一组测试数据. 每组测试数据的第1行为一个整数N,意义如前文所述. 每组测试数据的第2行为N个整数,分别描述每种商品的重量,其中第i个整数表示标号为i的商品 ...

  6. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  7. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  8. 【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法

    C. Sasha and Array time limit per test:5 seconds memory limit per test:256 megabytes input:standard ...

  9. 【Codeforces717F】Heroes of Making Magic III 线段树 + 找规律

    F. Heroes of Making Magic III time limit per test:3 seconds memory limit per test:256 megabytes inpu ...

  10. POJ 2528 Mayor's posters (线段树)

    题目链接:http://poj.org/problem?id=2528 题目大意:有一个很上的面板, 往上面贴海报, 问最后最多有多少个海报没有被完全覆盖 解题思路:将贴海报倒着想, 对于每一张海报只 ...

随机推荐

  1. spring boot 2.0集成并使用redis

    项目地址:https://gitee.com/indexman/spring_boot_in_action 前面一章介绍了spring boot自带的缓存,下面讲一下如何在2.0版本中集成并使用red ...

  2. win32改变静态控件的文本大小

    HWND static_ = CreateWindow(L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, 100, 100, 10 ...

  3. .net+bootstrap写的一个还不错的音乐网站

    以前做的一款设计音乐网站,分享下. 技术用的是.net +sqlserver 大致的样子是这样的. 1.首页如下: 2.播放歌词页面如下:歌词自动滚动,且可悬停. 3.歌单信息页面如下: 详细页面如下 ...

  4. 【.Net Core】.Net Core 源码分析与深入理解 - 配置中心 Startup.cs (二)

    源码版本: .Net Core 3.1.14 上篇文章: [.Net Core].Net Core 源码分析与深入理解 - 入口 Program.cs (一) 注意:本篇文章主要研究的是 Startu ...

  5. 被 AI 替代应该就在不远的将来

    提问:golang 各种图片 转 webp 代码 一秒之后...... package main import ( "fmt" "image" "im ...

  6. python基础安装虚拟环境

    1.pip install virtualenv或者pip3 install virtualenv 2.在要存放虚拟环境的地方创建一个venv文件夹,用来存放所有创建的虚拟环境,方便查找与管理 3.m ...

  7. 图查询语言 nGQL 简明教程 vol.01 快速入门

    本文旨在让新手快速了解 nGQL,掌握方向,之后可以脚踩在地上借助文档写出任何心中的 NebulaGraph 图查询. 视频 本教程的视频版在B站这里. 准备工作 在正式开始 nGQL 实操之前,记得 ...

  8. MVVM框架模式

    MVC框架模式 MVP框架模式 MVVM框架模式 MVVM模式即: 1.Model:数据层.网络数据操作,file文件操作,本地数据库操作: 2.View:视图层.布局加载,ui交互. 3.ViewM ...

  9. 聊聊微信小程序的流式(stream)响应请求

    场景:类似ChatGPT的逐字显示效果. 流程:服务端我用Python的flask框架(向外提供API接口)实现,服务部署在replit上,Python调用azure 的chatgpt服务(需要申请) ...

  10. 我的闲鱼Python爬虫接单总结和经验,最高600元一单

    最近,我在闲鱼上利用 Python 爬虫技术接了一些任务,想必你一定好奇,通过这样的方式,到底能不能挣钱,能挣多少钱?今天我就来分享一下我的经验和总结. 一.接单经历 之前 Vue 的作者尤大在微博上 ...