线段树基础
来源:互联网 发布:ubuntu 在线音乐 编辑:程序博客网 时间:2024/05/21 18:35
1.线段树的构造
线段树是一棵二叉树,他的每个节点包含了两个额外的属性start
和end
用于表示该节点所代表的区间。start和end都是整数,并按照如下的方式赋值:
- 根节点的 start 和 end 由
build
方法所给出。 - 对于节点 A 的左儿子,有
start=A.left, end=(A.left + A.right) / 2
。 - 对于节点 A 的右儿子,有
start=(A.left + A.right) / 2 + 1, end=A.right
。 - 如果 start 等于 end, 那么该节点是叶子节点,不再有左右儿子。
实现一个 build
方法,接受 start 和 end 作为参数, 然后构造一个代表区间 [start, end]
的线段树,返回这棵线段树的根。
比如给定start=1, end=6
,对应的线段树为:
[1, 6] / \ [1, 3] [4, 6] / \ / \ [1, 2] [3,3] [4, 5] [6,6] / \ / \[1,1] [2,2] [4,4] [5,5]
代码:class Solution {public: /** *@param start, end: Denote an segment / interval *@return: The root of Segment Tree */ SegmentTreeNode * build(int start, int end) { // write your code here if(end<start)return nullptr; SegmentTreeNode *t=new SegmentTreeNode(start,end); if(start!=end) {t->left=build(start,(start+end)/2); t->right=build((start+end)/2+1,end);} return t; }};
2.线段树的查询
对于一个有n个数的整数数组,在对应的线段树中, 根节点所代表的区间为0-n-1, 每个节点有一个额外的属性max
,值为该节点所代表的数组区间start到end内的最大值。
为SegmentTree设计一个 query
的方法,接受3个参数root
, start
和end
,线段树root所代表的数组中子区间[start, end]内的最大值。
对于数组 [1, 4, 2, 3]
, 对应的线段树为:
[0, 3, max=4] / \ [0,1,max=4] [2,3,max=3] / \ / \ [0,0,max=1] [1,1,max=4] [2,2,max=2], [3,3,max=3]
query(root, 1, 1), return 4
query(root, 1, 2), return 4
query(root, 2, 3), return 3
query(root, 0, 2), return 4
class Solution {public: /** *@param root, start, end: The root of segment tree and * an segment / interval *@return: The maximum number in the interval [start, end] */ int query(SegmentTreeNode *root, int start, int end) { // write your code here if(root->left==nullptr)return root->max; if(root->start>=start&&root->end<=end)return root->max; int mid=(root->start+root->end)/2; if(start>mid)return query(root->right,start,end); else if(end<=mid)query(root->left,start,end); else return max(query(root->left,start,mid),query(root->right,mid+1,end)); }};3.线段树的修改
For a Maximum Segment Tree
, which each node has an extra value max
to store the maximum value in this node's interval.
Implement a modify
function with three parameter root
, index
and value
to change the node's value with [start, end] = [index, index] to the new given value. Make sure after this change, every node in segment tree still has the max attribute with the correct value.
For segment tree:
[1, 4, max=3] / \ [1, 2, max=2] [3, 4, max=3] / \ / \[1, 1, max=2], [2, 2, max=1], [3, 3, max=0], [4, 4, max=3]
if call modify(root, 2, 4)
, we can get:
[1, 4, max=4] / \ [1, 2, max=4] [3, 4, max=3] / \ / \[1, 1, max=2], [2, 2, max=4], [3, 3, max=0], [4, 4, max=3]
or call modify(root, 4, 0)
, we can get:
[1, 4, max=2] / \ [1, 2, max=2] [3, 4, max=0] / \ / \[1, 1, max=2], [2, 2, max=1], [3, 3, max=0], [4, 4, max=0]
class Solution {public: /** *@param root, index, value: The root of segment tree and *@ change the node's value with [index, index] to the new given value *@return: void */ void modify(SegmentTreeNode *root, int index, int value) { // write your code here if(root->start==index&&root->end==index) { root->max=value; } else if(root->left==nullptr)return; else { modify(root->left,index,value); modify(root->right,index,value); root->max=max(root->left->max,root->right->max); } }};4.区间最小数
给定一个整数数组(下标由 0 到 n-1,其中 n 表示数组的规模),以及一个查询列表。每一个查询列表有两个整数 [start, end]
。 对于每个查询,计算出数组中从下标 start 到 end 之间的数的最小值,并返回在结果列表中。
对于数组 [1,2,7,8,5]
, 查询 [(1,2),(0,4),(2,4)]
,返回 [2,1,5]
/** * Definition of Interval: * classs Interval { * int start, end; * Interval(int start, int end) { * this->start = start; * this->end = end; * } */ class tree { public: int start, end, min; tree *left, *right; tree(int start, int end) { this->start = start; this->end = end; this->min = min; this->left = this->right = NULL; } };class Solution { public: /** *@param A, queries: Given an integer array and an query list *@return: The result list */ tree* build(vector<int> &A,int start,int end) { if(start==end) { tree*t=new tree(start,end); t->min=A[start]; return t; } int mid=(start+end)/2; tree*t=new tree(start,end); t->left=build(A,start,mid); t->right=build(A,mid+1,end); t->min=min(t->left->min,t->right->min); return t; } int query(tree*t,int start,int end) { int mid=(t->start+t->end)/2; if(start<=t->start&&end>=t->end)return t->min; else if(end<=mid)return query(t->left,start,end); else if(start>mid)return query(t->right,start,end); else return min(query(t->left,start,mid),query(t->right,mid+1,end)); } vector<int> intervalMinNumber(vector<int> &A, vector<Interval> &queries) { // write your code here int len=A.size(); vector<int>ret; tree*t=build(A,0,len-1); for(int i=0;i<queries.size();i++) { tree*t1=t; Interval val=queries[i]; int start=val.start; int end=val.end; ret.push_back(query(t1,start,end)); } return ret; }};
5.区间求和
在类的构造函数中给一个整数数组, 实现两个方法 query(start, end)
和 modify(index, value)
:
- 对于 query(start, end), 返回数组中下标 start 到 end 的 和。
- 对于 modify(index, value), 修改数组中下标为 index 上的数为 value.
给定数组 A = [1,2,7,8,5]
.
query(0, 2)
, 返回10
.modify(0, 4)
, 将 A[0] 修改为 4.query(0, 1)
, 返回6
.modify(2, 1)
, 将 A[2] 修改为 1.query(2, 4)
, 返回14
.
class mytree{ public: int start,end; long long sum; mytree* left,*right; mytree(int start,int end) { this->start=start; this->end=end; this->left=this->right=nullptr; this->sum=0; }};class Solution {public: /* you may need to use some attributes here */ /** * @param A: An integer vector */ mytree*t; mytree* build(vector<int>&nums,int start,int end) { if(start==end) { mytree *t1=new mytree(start,end); t1->sum=nums[start]; return t1; } else { mytree *t1=new mytree(start,end); int mid=(start+end)/2; t1->left=build(nums,start,mid); t1->right=build(nums,mid+1,end); t1->sum=t1->left->sum+t1->right->sum; return t1; } } Solution(vector<int> A) { // write your code here if(A.size()==0)t=nullptr; else{ int start=0; int end=A.size()-1; t=build(A,start,end); } } /** * @param start, end: Indices * @return: The sum from start to end */ long long query(int start, int end) { // write your code here if(t==nullptr)return 0; return q(t,start,end); } long long q(mytree*&t,int start,int end) { if(start==t->start&&end==t->end)return t->sum; else { int mid=(t->start+t->end)/2; if(start>mid)return q(t->right,start,end); else if(end<=mid)return q(t->left,start,end); else return q(t->right,mid+1,end)+q(t->left,start,mid); } } /** * @param index, value: modify A[index] to value. */ void modify(int index, int value) { // write your code here if(t) m(t,index,value); } void m(mytree *&t,int index,int value) { if(index==t->start&&index==t->end) { t->sum=value; } else { int mid=(t->start+t->end)/2; if(index<=mid) { m(t->left,index,value); t->sum=t->left->sum+t->right->sum; } else { m(t->right,index,value); t->sum=t->left->sum+t->right->sum; } } }};
6.统计前面比自己小的数的个数
给定一个整数数组 (下标由 0 到 n-1,其中 n 表示数组的规模,数值范围由 0 到 10000),以及一个 查询列表。对于每一个查询,将会给你一个整数,请你返回该数组中小于给定整数的元素的数量。
对于数组 [1,2,7,8,5]
,查询 [1,8,5]
,返回 [0,4,2]
class mytree{ public: int start,end; int count; mytree* left,*right; mytree(int start,int end) { this->start=start; this->end=end; this->left=this->right=nullptr; this->count=0; } }; class Solution {public: /** * @param A: An integer array * @return: Count the number of element before this element 'ai' is * smaller than it and return count number array */ mytree* build(int start,int end) { if(start==end) { mytree *t1=new mytree(start,end); return t1; } else { mytree *t1=new mytree(start,end); int mid=(start+end)/2; t1->left=build(start,mid); t1->right=build(mid+1,end); return t1; } } void insert(mytree*&t,int index) { if(t->start==t->end&&t->start==index) (t->count)++; else { int mid=(t->start+t->end)/2; if(index>mid)insert(t->right,index); else if(index<=mid)insert(t->left,index); t->count=t->left->count+t->right->count; } } int query(mytree*t,int start,int end) { if(start>end)return 0; if(start<=t->start&&end>=t->end)return t->count; else { int mid=(t->start+t->end)/2; if(mid<start)return query(t->right,start,end); else if(mid>=end)return query(t->left,start,end); else return query(t->left,start,mid)+query(t->right,mid+1,end); } } vector<int> countOfSmallerNumberII(vector<int> &A) { // write your code here if(A.size()==0)return vector<int>{}; vector<int>ret; mytree*t=build(0,10005); for(int i=0;i<A.size();i++) { if(A[i]==0) { ret.push_back(0); insert(t,0); } else{ ret.push_back(query(t,0,A[i]-1)); insert(t,A[i]); } } return ret; }};
- 线段树基础
- 基础线段树
- 线段树基础题
- 线段树 基础
- 线段树基础篇
- POJ2528线段树基础
- 线段树基础
- 线段树基础 poj2104
- 线段树基础 poj2352
- 线段树基础
- 算法基础 - 线段树
- 线段树-基础
- HDU1556 - 线段树基础
- 线段树基础总结
- 线段树基础入门
- 线段树基础
- 线段树(基础)
- 线段树基础
- 打印文本中长度为n的字符串-Linux
- Install Skype 4.3 on RHEL7.3
- Laravel Blade模板引擎
- java百度地图瓦片批量下载demo
- Eclipse配置Axis2总结
- 线段树基础
- android 集成第三方静态库的编译方法
- SAP Classification(物料特性)
- 【java】log4j日志初始和使用
- 蚂蚁金服CTO程立:从Fintech到Techfin,未来十年有九大重要挑
- 将dataGridView中的数据导出到Excel中
- 跟我一起写udev规则(译)
- MFC橡皮筋矩形框技术
- idea14 的cannot resolve symbol‘servlet’