题目
在类的构造函数中给一个整数数组, 实现两个方法 query(start, end) 和 modify(index, value):
对于 query(start, end), 返回数组中下标 start 到 end 的 和。
对于 modify(index, value),把数组中下标为 index 的数改为 value.
样例
样例1
输入:
[1,2,7,8,5]
[query(0,2),modify(0,4),query(0,1),modify(2,1),query(2,4)]
输出: [10,6,14]
说明:
给定数组 A = [1,2,7,8,5].
在query(0, 2)后, 1 + 2 + 7 = 10,
在modify(0, 4)后, 将 A[0] 修改为 4, A = [4,2,7,8,5].
在query(0, 1)后, 4 + 2 = 6.
在modify(2, 1)后, 将 A[2] 修改为 1,A = [4,2,1,8,5].
After query(2, 4), 1 + 8 + 5 = 14.
样例2
输入:
[1,2,3,4,5]
[query(0,0),query(1,2),quert(3,4)]
输出: [1,5,9]
说明:
1 = 1
2 + 3 = 5
4 + 5 = 9
分析
一道完整的区间和线段树,包括增删改查的功能
代码部分
1.线段树节点
//线段树节点
class SegmentTreeNode
{
public:
SegmentTreeNode* left;
SegmentTreeNode* right;
long long value,start,end;
SegmentTreeNode(int s,int e,int v):start(s),end(e),value(v)
{
left=NULL;
right=NULL;
}
};
2.线段树的构造
特判一下数组大小为0时返回NULL,start>end时返回NULL
当叶子节点时,直接构造线段树节点并返回
递归的深入左右节点
回溯时构造当前节点
SegmentTreeNode* build(int start,int end,vector<int> nums)
{
//出口
if(nums.size()==0) //特判
return NULL;
if(start>end)
return NULL;
if(start==end)
{
return new SegmentTreeNode(start,end,nums[start]);
}
SegmentTreeNode* _root=new SegmentTreeNode(start,end,0);
//现在能做的事情
int mid=(start+end)/2;
_root->left=build(start,mid,nums);
_root->right=build(mid+1,end,nums);
if(_root->left!=NULL)
_root->value+=_root->left->value;
if(_root->right!=NULL)
_root->value+=_root->right->value;
return _root;
}
3.线段树的查询
现在能做的事情:递归的深入求左右两个节点之和并返回
出口:当前范围和查找范围没有重合部分时直接返回0,当前范围在查找范围内时,直接返回当前节点的值
long long query(SegmentTreeNode* root,
int start,int end,int qstart,int qend) //查询
{
//出口
if(end<qstart||start>qend)
return 0;
if(start>=qstart&&end<=qend)
return root->value;
//现在能做的事情
int mid=(start+end)/2;
return query(root->left,start,mid,qstart,qend)+
query(root->right,mid+1,end,qstart,qend);
}
4.线段树的修改
现在能做的事情:根据修改的下标,来递归的深入左分支或者右分支,修改后回溯的修改它的父节点
出口:达到叶子节点,且下标为目标下标
void modify(SegmentTreeNode* _root,
int start,int end,int index,int value)
{
//出口
if(start==end&&start==index)
{
_root->value=value;
return ;
}
//现在能做的事情
int mid=(start+end)/2;
if(index<=mid)
modify(_root->left,start,mid,index,value);
else
modify(_root->right,mid+1,end,index,value);
//回溯
_root->value=_root->left->value+_root->right->value;
}
};
完整代码
#include <bits/stdc++.h>
using namespace std;
//线段树节点
class SegmentTreeNode
{
public:
SegmentTreeNode* left;
SegmentTreeNode* right;
long long value,start,end;
SegmentTreeNode(int s,int e,int v):start(s),end(e),value(v)
{
left=NULL;
right=NULL;
}
};
//线段树
class SegmentTree
{
public:
SegmentTreeNode* root;
SegmentTree()
{
}
SegmentTree(vector<int> nums)
{
root=build(0,nums.size()-1,nums);
}
SegmentTreeNode* build(int start,int end,vector<int> nums)
{
//出口
if(nums.size()==0) //特判
return NULL;
if(start>end)
return NULL;
if(start==end)
{
return new SegmentTreeNode(start,end,nums[start]);
}
SegmentTreeNode* _root=new SegmentTreeNode(start,end,0);
//现在能做的事情
int mid=(start+end)/2;
_root->left=build(start,mid,nums);
_root->right=build(mid+1,end,nums);
if(_root->left!=NULL)
_root->value+=_root->left->value;
if(_root->right!=NULL)
_root->value+=_root->right->value;
return _root;
}
long long query(SegmentTreeNode* root,
int start,int end,int qstart,int qend) //查询
{
//出口
if(end<qstart||start>qend)
return 0;
if(start>=qstart&&end<=qend)
return root->value;
//现在能做的事情
int mid=(start+end)/2;
return query(root->left,start,mid,qstart,qend)+
query(root->right,mid+1,end,qstart,qend);
}
void modify(SegmentTreeNode* _root,
int start,int end,int index,int value)
{
//出口
if(start==end&&start==index)
{
_root->value=value;
return ;
}
//现在能做的事情
int mid=(start+end)/2;
if(index<=mid)
modify(_root->left,start,mid,index,value);
else
modify(_root->right,mid+1,end,index,value);
//回溯
_root->value=_root->left->value+_root->right->value;
}
};
class Solution {
public:
vector<int> nums;
SegmentTree st;
Solution(vector<int> A) {
nums=A;
SegmentTree tmp(A);
st=tmp;
}
long long query(int start, int end) {
return st.query(st.root,0,nums.size()-1,start,end);
}
void modify(int index, int value) {
st.modify(st.root,0,nums.size()-1,index,value);
}
};
int main (void)
{
vector<int> A={10};
Solution s(A);
cout<<s.query(0,0)<<" ";
s.modify(0,9);
cout<<s.query(0,0)<<" ";
return 0;
}
总结
这道题被标记为困难题,但是如果熟练线段树的模板,我觉得应该算是简单题
完整版的线段树,也是一个经典的模板,要做到倒背如流的程度