(完整版线段树)lintcode困难207 · 区间求和 II

题目

在类的构造函数中给一个整数数组, 实现两个方法 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;
}







总结

这道题被标记为困难题,但是如果熟练线段树的模板,我觉得应该算是简单题
完整版的线段树,也是一个经典的模板,要做到倒背如流的程度

May you succeed

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

White boy&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值