文章目录

  • 1. 概念
  • 2. 建树
  • 3. 查询
  • 4. 修改
  • 5. 完整代码及测试

上图 from 熊掌搜索

  • 类似数据结构:树状数组

1. 概念

线段树是一种二叉树,是用来表示一个区间的树:

  • 常常用来查询区间的:和、最小值、最大值
  • 树结点中存放不是普通二叉树的值,其结点结构如下
class TreeNode
{public:int sum;//区间和int MAX;//区间最大的int MIN;//区间最小的int start, end;//区间左右端点TreeNode *left, *right;//左右节点TreeNode(int s, int e, int v):start(s),end(e),sum(v){left = right = NULL;MAX = v;MIN = v;}
};

2. 建树

  • 传入数组,及其左右极限端点
  • 自底向上建树
 TreeNode* build(vector<int>& A, int L, int R){if(L > R)return NULL;TreeNode* rt = new TreeNode(L,R,A[L]);if(L == R)return rt;int mid = L+((R-L)>>1);//对半分开rt->left = build(A,L,mid);rt->right = build(A,mid+1,R);rt->sum = 0;if(rt->left){rt->sum += rt->left->sum;rt->MAX = max(rt->MAX, rt->left->MAX);rt->MIN = min(rt->MIN, rt->left->MIN);}if(rt->right){rt->sum += rt->right->sum;rt->MAX = max(rt->MAX, rt->right->MAX);rt->MIN = min(rt->MIN, rt->right->MIN);}return rt;}

3. 查询

  • 时间复杂度:O(log⁡n)O(\log n)O(logn)
 vector<int> query(TreeNode *rt, int s, int e)//查询区间的sum,min,max{if(s > rt->end || e < rt->start)return {0, INT_MAX, INT_MIN};//没有交集if(s <= rt->start && rt->end <= e)return {rt->sum, rt->MIN, rt->MAX};//完全包含区间,取其值//不完全包含,左右查找vector<int> l = query(rt->left, s, e);vector<int> r = query(rt->right,s, e);//汇总信息vector<int> summary(3);summary[0] = l[0] + r[0];summary[1] = min(l[1], r[1]);summary[2] = max(l[2], r[2]);return summary;}

4. 修改

  • 时间复杂度:O(log⁡n)O(\log n)O(logn)
 void modify(TreeNode *rt, int id, int val){if(rt->start == rt->end){    //叶子节点rt->sum = val;//和为自身rt->MAX = val;rt->MIN = val;data[id] = val;return;}int mid = (rt->start + rt->end)/2;if(id > mid)modify(rt->right, id, val);elsemodify(rt->left, id, val);root->sum = 0;if(rt->left){rt->sum += rt->left->sum;rt->MAX = max(rt->MAX, rt->left->MAX);rt->MIN = min(rt->MIN, rt->left->MIN);}if(rt->right){rt->sum += rt->right->sum;rt->MAX = max(rt->MAX, rt->right->MAX);rt->MIN = min(rt->MIN, rt->right->MIN);}}

5. 完整代码及测试

/*** @description: 线段树* @author: michael ming* @date: 2020/3/13 0:21* @modified by:* @Website: https://michael.blog.csdn.net/*/
#include<vector>
#include<iostream>
#include<climits>
using namespace std;
class TreeNode
{public:int sum;//区间和int MAX;//区间最大的int MIN;//区间最小的int start, end;//区间左右端点TreeNode *left, *right;//左右节点TreeNode(int s, int e, int v):start(s),end(e),sum(v){left = right = NULL;MAX = v;MIN = v;}
};
class SegmentTree
{public:TreeNode* root;vector<int> data;SegmentTree(vector<int>& A){root = build(A, 0, A.size()-1);data = A;}~SegmentTree(){destroy(root);}void destroy(TreeNode* rt){if(!rt) return;destroy(rt->left);destroy(rt->right);delete rt;}TreeNode* build(vector<int>& A, int L, int R){if(L > R)return NULL;TreeNode* rt = new TreeNode(L,R,A[L]);if(L == R)return rt;int mid = L+((R-L)>>1);//对半分开rt->left = build(A,L,mid);rt->right = build(A,mid+1,R);rt->sum = 0;if(rt->left){rt->sum += rt->left->sum;rt->MAX = max(rt->MAX, rt->left->MAX);rt->MIN = min(rt->MIN, rt->left->MIN);}if(rt->right){rt->sum += rt->right->sum;rt->MAX = max(rt->MAX, rt->right->MAX);rt->MIN = min(rt->MIN, rt->right->MIN);}return rt;}vector<int> query(TreeNode *rt, int s, int e)//查询区间的sum,min,max{if(s > rt->end || e < rt->start)return {0, INT_MAX, INT_MIN};//没有交集if(s <= rt->start && rt->end <= e)return {rt->sum, rt->MIN, rt->MAX};//完全包含区间,取其值//不完全包含,左右查找vector<int> l = query(rt->left, s, e);vector<int> r = query(rt->right,s, e);//汇总信息vector<int> summary(3);summary[0] = l[0] + r[0];summary[1] = min(l[1], r[1]);summary[2] = max(l[2], r[2]);return summary;}void modify(TreeNode *rt, int id, int val){if(rt->start == rt->end){  //叶子节点rt->sum = val;//和为自身rt->MAX = val;rt->MIN = val;data[id] = val;return;}int mid = (rt->start + rt->end)/2;if(id > mid)modify(rt->right, id, val);elsemodify(rt->left, id, val);root->sum = 0;if(rt->left){rt->sum += rt->left->sum;rt->MAX = max(rt->MAX, rt->left->MAX);rt->MIN = min(rt->MIN, rt->left->MIN);}if(rt->right){rt->sum += rt->right->sum;rt->MAX = max(rt->MAX, rt->right->MAX);rt->MIN = min(rt->MIN, rt->right->MIN);}}
};
//-------------test---------------------
void printVec(vector<int> &a)
{for(auto& ai : a)cout << ai << " ";cout << endl;
}int main()
{vector<int> v = {1,2,7,8,5};printVec(v);cout << "建立线段树" << endl;SegmentTree sgtree(v);printVec(sgtree.data);cout << "查询区间的sum,MIN,MAX" << endl;vector<int> qy_res = sgtree.query(sgtree.root,1,3);printVec(qy_res);cout << "修改某位置的值" << endl;sgtree.modify(sgtree.root,1,100);printVec(sgtree.data);cout << "查询区间的sum,MIN,MAX" << endl;qy_res = sgtree.query(sgtree.root,1,3);printVec(qy_res);return 0;
}

运行结果:valgrind ./a.out

==16895== Memcheck, a memory error detector
==16895== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16895== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==16895== Command: ./a.out
==16895==
1 2 7 8 5
建立线段树
1 2 7 8 5
查询区间的sum,MIN,MAX
17 2 8
修改某位置的值
1 100 7 8 5
查询区间的sum,MIN,MAX
115 7 100
==16895==
==16895== HEAP SUMMARY:
==16895==     in use at exit: 0 bytes in 0 blocks
==16895==   total heap usage: 29 allocs, 29 frees, 616 bytes allocated
==16895==
==16895== All heap blocks were freed -- no leaks are possible
==16895==
==16895== For counts of detected and suppressed errors, rerun with: -v
==16895== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
  • 相关题目:LintCode 207. 区间求和 II(hard)

数据结构--树--线段树(Segment Tree)相关推荐

  1. 307. Range Sum Query - Mutable | 307. 区域和检索 - 数组可修改(数据结构:线段树,图文详解)

    题目 https://leetcode.com/problems/range-sum-query-mutable/ 吐槽官方题解 这题的 英文版官方题解,配图和代码不一致,而且描述不清:力扣国内版题解 ...

  2. 0x43.数据结构进阶 - 线段树

    目录 一.基础线段树 线段树的建树 线段树的单点修改 线段树的区间查询 线段树的延迟标记(懒惰标记) 1.POJ3486 ASimpleProblemwithIntegersA\ Simple\ Pr ...

  3. 树套树-线段树套平衡树

    作用 线段树的作用是区间修改和查询,平衡树的作用是查询第k大,k的排名,前驱,后继.这两个结合起来,就变成了可以区间修改和查询第k大,k的排名,前驱,后继的数据结构:树套树-线段树套平衡树. 实现 先 ...

  4. 数据结构之线段树合并——永无乡,Lomsat gelral,Tree Rotations,Tree Rotations Escape Through Leaf

    文章目录 [HNOI2012]永无乡 Lomsat gelral 「POI2011 R2 Day2」旋转树木 Tree Rotations Escape Through Leaf 线段树合并与 fhq ...

  5. 【数据结构】线段树(interval tree)

    线段树(interval tree),也叫区间树.也是一种二叉搜索树,同一般的BST不同之处在于:线段树的每一个结点包含的是一个区间而不是一个数.具体的描述如下: 从图上可以看出,线段树的每一个结点都 ...

  6. c++ 数据结构之 线段树

    线段树是一种数据结构,是一种二叉树.线段树将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点.线段树对于区间求和等区间操作能够实现复杂度为O(logn)的操作,故得以广泛利用.修改一个 ...

  7. 【数据结构】线段树的扩展与应用

    线段树是一种非常基础的数据结构,但有的时候仅仅是普通的线段树无法满足需求,那么我们就要对其进行一些扩展. Chapter1:标记永久化 实现 普通的线段树通过懒标记(Lazy Tag)以 O ( n ...

  8. 数据结构之线段树入门(单点更新区间查询)

    线段树是学习数据结构必须学习的一种数据结构,在ACM,蓝桥等比赛中是经常出现的.利用线段树解题,会使得题目简单易理解.而且线段树是数据结构中比较基础而且用的很多的一种. 线段树定义 线段树是一种二叉搜 ...

  9. 【地狱副本】数据结构之线段树Ⅲ——区间最值/赋值/修改/历史值操作(HDU5306,Tyvj 1518,【清华集训2015】V,HDU6315,HDU1828,POJ3162)

    文章目录 Gorgeous Sequence Tyvj 1518 CPU监控 [清华集训2015]V Naive Operations Picture Walking Race Gorgeous Se ...

最新文章

  1. Windows Mobile 与 PC之间的通过蓝牙(Bluetooth) 传输文件的开发
  2. .NET平台开源项目速览(3)小巧轻量级NoSQL文件数据库LiteDB
  3. java中的字符,字符串,数字之间的转换(亲测)
  4. Docker 网络基础原理
  5. Java集合类原理详解
  6. 剑指offer:39-42记录
  7. 记录下kaggle比赛经验
  8. 企业信息化管理有什么意义?
  9. Android的双进程守护,广播和双进程
  10. SQL:集成 SQL Server 2008 R2 SP3
  11. SIM800(GPRS)拨号上网失败未能连接服务器
  12. vivo X9的usb调试模式在哪里,开启vivo X9usb调试模式的方法
  13. 解决电脑因System进程而变得很卡
  14. 避免使用ordinal方法
  15. 统筹高效利用时间——《小强升职记(升级版):时间管理故事书》读后感
  16. word 分栏后转html,word文档分栏后的页码设置方法
  17. STM32CbueMX之USB挂载内存虚拟U盘
  18. 必过SafetyNet!以MIUI开发版系统为例详解Android设备通过SafetyNet校验方法
  19. 第十二届蓝桥杯 2021年省赛真题 (Java 大学A组) 第一场
  20. 2015级移动本面向对象课程主页

热门文章

  1. java服务器向客户端发消息_java一个简单的客户端向服务端发送消息
  2. C中关于存储类的理解
  3. MTK优美代码赏析6:电话本里的快速排序和插入排序算法
  4. 以下题目需要当场编写实现,,答案自己写
  5. bzoj1053: [HAOI2007]反素数ant
  6. 【项目总结】如何获取地图上的所有POI
  7. 提交app时候90475,90474
  8. 鼠标经过超链接文字变色
  9. InterDev 调试错误信息: Unable to set server into correct debugging state automatically....的解决办法...
  10. waveOutGetDevCaps - 查询输出设备的性能