<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>segment tree Archives - Huahua&#039;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/tag/segment-tree/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog/tag/segment-tree/</link>
	<description></description>
	<lastBuildDate>Mon, 12 Sep 2022 05:17:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.8</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>segment tree Archives - Huahua&#039;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog/tag/segment-tree/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>花花酱 LeetCode 2407. Longest Increasing Subsequence II</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 12 Sep 2022 05:16:09 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[range query]]></category>
		<category><![CDATA[segment tree]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9817</guid>

					<description><![CDATA[<p>You are given an integer array&#160;nums&#160;and an integer&#160;k. Find the longest subsequence of&#160;nums&#160;that meets the following requirements: The subsequence is&#160;strictly increasing&#160;and The difference between adjacent&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/">花花酱 LeetCode 2407. Longest Increasing Subsequence II</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You are given an integer array&nbsp;<code>nums</code>&nbsp;and an integer&nbsp;<code>k</code>.</p>



<p>Find the longest subsequence of&nbsp;<code>nums</code>&nbsp;that meets the following requirements:</p>



<ul><li>The subsequence is&nbsp;<strong>strictly increasing</strong>&nbsp;and</li><li>The difference between adjacent elements in the subsequence is&nbsp;<strong>at most</strong>&nbsp;<code>k</code>.</li></ul>



<p>Return<em>&nbsp;the length of the&nbsp;<strong>longest</strong>&nbsp;<strong>subsequence</strong>&nbsp;that meets the requirements.</em></p>



<p>A&nbsp;<strong>subsequence</strong>&nbsp;is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [4,2,1,4,3,4,5,8,15], k = 3
<strong>Output:</strong> 5
<strong>Explanation:</strong>
The longest subsequence that meets the requirements is [1,3,4,5,8].
The subsequence has a length of 5, so we return 5.
Note that the subsequence [1,3,4,5,8,15] does not meet the requirements because 15 - 8 = 7 is larger than 3.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [7,4,5,1,8,12,4,7], k = 5
<strong>Output:</strong> 4
<strong>Explanation:</strong>
The longest subsequence that meets the requirements is [4,5,8,12].
The subsequence has a length of 4, so we return 4.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [1,5], k = 1
<strong>Output:</strong> 1
<strong>Explanation:</strong>
The longest subsequence that meets the requirements is [1].
The subsequence has a length of 1, so we return 1.
</pre>



<p><strong>Constraints:</strong></p>



<ul><li><code>1 &lt;= nums.length &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= nums[i], k &lt;= 10<sup>5</sup></code></li></ul>



<h2><strong>Solution: DP + Segment Tree | Max range query</strong></h2>



<p>Let dp[i] := length of LIS end with number i.<br>dp[i] = 1 + max(dp[i-k:i])</p>



<p>Naive dp takes O(n*k) time which will cause TLE.</p>



<p>We can use segment tree to speed up the max range query to log(m), where m is the max value of the array.</p>



<p>Time complexity: O(n*logm)<br>Space complexity: O(m)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
class Solution {
public:
  int lengthOfLIS(vector&lt;int&gt;&amp; nums, int k) {
    const int n = *max_element(begin(nums), end(nums));
    vector&lt;int&gt; dp(2 * (n + 1));
    auto query = [&amp;](int l, int r) -&gt; int {
      int ans = 0;
      for (l += n, r += n; l &lt; r; l &gt;&gt;= 1, r &gt;&gt;= 1) {
        if (l &amp; 1) ans = max(ans, dp[l++]);      
        if (r &amp; 1) ans = max(ans, dp[--r]);
      }
      return ans;
    };
    auto update = [&amp;](int i, int val) -&gt; void {
      dp[i += n] = val;
      while (i &gt; 1) {
        i &gt;&gt;= 1;
        dp[i] = max(dp[i * 2], dp[i * 2 + 1]);
      }
    };        
    int ans = 0;
    for (int x : nums) {
      int cur = 1 + query(max(1, x - k), x);
      update(x, cur);
      ans = max(ans, cur);
    }
    return ans;
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/">花花酱 LeetCode 2407. Longest Increasing Subsequence II</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 Segment Tree 线段树 SP14</title>
		<link>https://zxi.mytechroad.com/blog/sp/segment-tree-sp14/</link>
					<comments>https://zxi.mytechroad.com/blog/sp/segment-tree-sp14/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Wed, 30 Jan 2019 16:41:06 +0000</pubDate>
				<category><![CDATA[SP]]></category>
		<category><![CDATA[O(logn)]]></category>
		<category><![CDATA[range sum]]></category>
		<category><![CDATA[segment tree]]></category>
		<category><![CDATA[tree]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=4738</guid>

					<description><![CDATA[<p>Segment tree is a balanced binary tree with O(logn) height given n input segments.Segment tree supports fast range query O(logn + k), and update O(logn).Building&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/sp/segment-tree-sp14/">花花酱 Segment Tree 线段树 SP14</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe width="500" height="375" src="https://www.youtube.com/embed/rYBtViWXYeI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></figure>



<p>Segment tree is a balanced binary tree with O(logn) height given n input segments.<br>Segment tree supports fast range query O(logn + k), and update O(logn).<br>Building such a tree takes O(n) time if the input is an array of numbers.</p>



<p>Tree之所以大行其道就是因为其结构和人类组织结构非常接近。就拿公司来说好了，CEO统领全局(root)，下面CTO，CFO等各自管理一个部门，每个部门下面又正好有好两个VP，每个VP下面又有两个director，每个director下面又有2个manager，每个manager下面又有2个底层员工(leaf)，为什么是2？因为我们用二叉树啊~</p>



<p>故事还是要从LeetCode 307. Range Sum Query &#8211; Mutable说起。</p>



<p>题目大意是：给你一个数组，再给你一个范围，让你求这个范围内所有元素的和，其中元素的值是可变的，通过update(index, val)更新。&nbsp;</p>



<p>nums = [1, 3, 5]，<br>sumRange(0, 2) = 1+3+5 = 9<br>update(1, 2) =&gt; [1, 2, 5]<br>sumRange(0, 2) = 1 + 2 + 5 = 7</p>



<p>暴力求解就是扫描一下这个范围。</p>



<p>时间复杂度：Update O(1), Query O(n)。</p>



<p>如果数组元素不变的话（303题），我们可以使用动态规划求出前n个元素的和然后存在sums数组中。i到j所有元素的和等于0~j所有元素的和减去0~(i-1)所有元素的和，即：</p>



<p>sumRange(i, j) := sums[j] &#8211; sums[i &#8211; 1] if i &gt; 0 else sums[j]</p>



<p>这样就可以把query的时间复杂度降低到O(1)。</p>



<p>但是这道题元素的值可变，那么就需要维护sums，虽然可以把query的时间复杂度降低到了O(1)，但update的时间复杂度是O(n)，并没有比暴力求解快。</p>



<p>这个时候就要请出我们今天的主人公Segment Tree了，可以做到</p>



<p>Update: O(logn)，Query: O(logn+k)</p>



<p>其实Segment Tree的思想还是很好理解的，比我们之前讲过的Binary Indexed Tree要容易理解的多（回复&nbsp;<strong>SP3</strong>&nbsp;获取视频），但是代码量又是另外一回事情了&#8230;</p>



<p>回到一开始讲的公司组织结构上面，假设一个公司有200个底层员工，</p>



<p>最原始的信息（元素的值）只掌握在他们工手里，层层上报。每个manager把他所管理的人的元素值求和之后继续上报，直到CEO。CEO知道但仅知道0-199的和。</p>



<p>当你问CEO，5到199的和是多少？他手上只有0-199的和，一下子慌了，赶紧找来CTO，CFO说你们把5到199的和给报上来，CFO一看报表，心中暗喜：还好我负责的这个区间(100~199)已经计算过了，就直接把之前的总和上报了。CTO一看报表，自己负责0-99这个区间，只知道0-99的和，但5-99的和，还是问下面的人吧&#8230; 最后结果再一层层返回给CEO。</p>



<p>说到这里大家应该已经能想象Segment Tree是怎么工作了吧：</p>



<p>每个leaf负责一个元素的值</p>



<p>每个parent负责的范围是他的children所负责的范围的union，并把所有范围内的元素值相加。</p>



<p>同一层的节点没有overlap。</p>



<p>root存储的是所有元素的和。</p>



<p>所以一个SegmentTreeNode需要记录以下信息</p>



<p>start #起始范围<br>end #终止范围<br>mid #拆分点，通常是 (start + end) // 2<br>val #所有子元素的和<br>left #左子树<br>right #右子树</p>



<p>Update: 由于每次只更新一个元素的值，所以CEO知道这个员工是哪个人管的，派发下去就行了，然后把新的结果再返回回来。</p>



<pre class="crayon-plain-tag">def update(root, index, val):
  # 到底层员工了，直接更新
  if root.start == index and root.end == index:
    root.val = val
    return
  # 根据拆分点，更新左子树或右子树
  if val &lt;= root.mid:
    update(root.left, index, val)
  else:
    update(root.right, index, val)
  # 重新计算和
  root.val = root.left?.val + root.right?.val</pre>



<p>T(n) = T(n/2) + 1 =&gt; O(logn)</p>



<p>Query: query的range可以是任意的，就有以下三种情况：</p>



<p>case 1: 这个range正好和我负责的range完全相同。比如sumQuery(CTO, 0, 99)，这个时候CTO直接返回已经求解过的所有下属的和即可。</p>



<p>case 2: 这个range只由我其中一个下属负责。比如sumQuery(CEO, 0, 10)，CEO知道0~10全部由CFO负责，那么他就直接返回sumQuery(CTO, 0, 10)。</p>



<p>case 3: 这个range覆盖了我的两个下属，那么我就需要调用2次。比如sumQuery(CEO, 80, 120)，CEO知道0~99由CTO管，100~199由CFO管，所以他只需要返回：</p>



<p>sumQuery(CTO, 80, 99) + sumQuery(CFO, 100, 120)<br></p>



<p>由此可见sumQuery的时间复杂度是不确定的，运气好时O(1)，运气不好时是O(logn+k)，k是需要访问的节点的数量。 </p>



<p>我做了一个实验，给定N，尝试所有的(i,j)组合，看sumQuery的最坏情况和平均情况，结果如下图：</p>



<figure class="wp-block-image"><img width="600" height="371" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/02/query_nodes.png" alt="" class="wp-image-4795" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/02/query_nodes.png 600w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/02/query_nodes-300x186.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></figure>



<p>Query需要访问到的节点数量的worst和average case。Worst case 大约访问 4*logn &#8211; 3 个节点，这个数字远远小于n。和n成对数关系。<br></p>



<p>虽然不像Binary Indexed Tree query是严格的O(logn)，但Segment tree query的worst case增长的非常慢，可以说是对数级别的。当N是2^20的时候，worst case也“只需要”访问77个节点。</p>



<p>最后我们再来讲一下这棵树是怎么创建的，其实方法有很多种，一分为二是比较常规的一种做法。</p>



<p>CEO管200人，那么就找2个人(CTO，CFO各管100人。CTO管100人，再找2个VP各管50人，以此类推，直到manager管2个人，2个人都是底层员工(leaf)，没有人管（双关）。</p>



<pre class="crayon-plain-tag">def buildTree(start, end):
  # 超过范围返回空节点
  if start &amp;gt; end: return None
  boss.start = start
  boss.end = end
  # 如果是叶子节点，记录元素的值
  if start == end: boss.val = nums[start]
  boss.mid = (start + end) // 2
  # 递归构建子树
  boss.left = buildTree(start, mid)
  boss.right = buildTree(mid + 1, end)
  # 求和
  boss.val += boss.left?.val + boss.right?.val
  return boss</pre>



<p>CEO = buildTree(0, 199)</p>



<p>CEO.left # CTO 负责0~99<br>CEO.right # CFO&nbsp;负责100~199</p>



<hr class="wp-block-separator is-style-wide"/>



<figure class="wp-block-image"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-1.png" alt="" class="wp-image-4739" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-1-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<figure class="wp-block-image"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-2.png" alt="" class="wp-image-4740" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-2-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<figure class="wp-block-image"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-3.png" alt="" class="wp-image-4741" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-3-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<figure class="wp-block-image"><img width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-4.png" alt="" class="wp-image-4742" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-4.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-4-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2019/01/sp14-4-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></figure>



<p>Query: # of nodes visited: Average and worst are both ~O(logn)</p>



<h2>Applications</h2>



<p><a href="https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/">LeetCode&nbsp;307&nbsp;Range&nbsp;Sum&nbsp;Query&nbsp;&#8211;&nbsp;Mutable</a></p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, running time: 24 ms
class SegmentTreeNode {
public:
  SegmentTreeNode(int start, int end, int sum,
                  SegmentTreeNode* left = nullptr,
                  SegmentTreeNode* right = nullptr): 
    start(start),
    end(end),
    sum(sum),
    left(left),
    right(right){}      
  SegmentTreeNode(const SegmentTreeNode&amp;) = delete;
  SegmentTreeNode&amp; operator=(const SegmentTreeNode&amp;) = delete;
  ~SegmentTreeNode() {
    delete left;
    delete right;
    left = right = nullptr;
  }
  
  int start;
  int end;
  int sum;
  SegmentTreeNode* left;
  SegmentTreeNode* right;
};

class NumArray {
public:
  NumArray(vector&lt;int&gt; nums) {
    nums_.swap(nums);
    if (!nums_.empty())
      root_.reset(buildTree(0, nums_.size() - 1));
  }

  void update(int i, int val) {
    updateTree(root_.get(), i, val);
  }

  int sumRange(int i, int j) {
    return sumRange(root_.get(), i, j);
  }
private:
  vector&lt;int&gt; nums_;
  std::unique_ptr&lt;SegmentTreeNode&gt; root_;
  
  SegmentTreeNode* buildTree(int start, int end) {  
    if (start == end) {      
      return new SegmentTreeNode(start, end, nums_[start]);
    }
    int mid = start + (end - start) / 2;
    auto left = buildTree(start, mid);
    auto right = buildTree(mid + 1, end);
    auto node = new SegmentTreeNode(start, end, left-&gt;sum + right-&gt;sum, left, right);    
    return node;
  }
  
  void updateTree(SegmentTreeNode* root, int i, int val) {
    if (root-&gt;start == i &amp;&amp; root-&gt;end == i) {
      root-&gt;sum = val;
      return;
    }
    int mid = root-&gt;start + (root-&gt;end - root-&gt;start) / 2;
    if (i &lt;= mid) {
      updateTree(root-&gt;left, i, val);
    } else {      
      updateTree(root-&gt;right, i, val);
    }
    root-&gt;sum = root-&gt;left-&gt;sum + root-&gt;right-&gt;sum;
  }
  
  int sumRange(SegmentTreeNode* root, int i, int j) {    
    if (i == root-&gt;start &amp;&amp; j == root-&gt;end) {
      return root-&gt;sum;
    }
    int mid = root-&gt;start + (root-&gt;end - root-&gt;start) / 2;
    if (j &lt;= mid) {
      return sumRange(root-&gt;left, i, j);
    } else if (i &gt; mid) {
      return sumRange(root-&gt;right, i, j);
    } else {
      return sumRange(root-&gt;left, i, mid) + sumRange(root-&gt;right, mid + 1, j);
    }
  }
};</pre>

</div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag"># Author: Huahua, running time: 176 ms
class SegmentTreeNode:
  def __init__(self, start, end, val, left=None, right=None):
    self.start = start
    self.end = end
    self.mid = start + (end - start) // 2
    self.val = val
    self.left = left
    self.right = right

class NumArray:
  def __init__(self, nums):
    self.nums = nums
    if self.nums:
      self.root = self._buildTree(0, len(nums) - 1)

  def update(self, i, val):      
    self._updateTree(self.root, i, val)

  def sumRange(self, i, j):
    return self._sumRange(self.root, i, j)
    
  
  def _buildTree(self, start, end):
    if start == end: return SegmentTreeNode(start, end, self.nums[start])
    mid = start + (end - start) // 2
    left = self._buildTree(start, mid)
    right = self._buildTree(mid + 1, end)
    return SegmentTreeNode(start, end, left.val + right.val, left, right)
  
  def _updateTree(self, root, i, val):
    if root.start == i and root.end == i:
      root.val = val
      return    
    if i &lt;= root.mid:
      self._updateTree(root.left, i, val)
    else:
      self._updateTree(root.right, i, val)
    root.val = root.left.val + root.right.val
  
  def _sumRange(self, root, i, j):
    if root.start == i and root.end == j:
      return root.val
    if j &lt;= root.mid:
      return self._sumRange(root.left, i, j)
    elif i &gt; root.mid:
      return self._sumRange(root.right, i, j)
    else:
      return self._sumRange(root.left, i, root.mid) + self._sumRange(root.right, root.mid + 1, j)</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/sp/segment-tree-sp14/">花花酱 Segment Tree 线段树 SP14</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/sp/segment-tree-sp14/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 307. Range Sum Query &#8211; Mutable</title>
		<link>https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/</link>
					<comments>https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/#comments</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 04 Jan 2018 05:27:14 +0000</pubDate>
				<category><![CDATA[Array]]></category>
		<category><![CDATA[Bit]]></category>
		<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[fenwick tree]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[prefix sum]]></category>
		<category><![CDATA[range sum]]></category>
		<category><![CDATA[segment tree]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=1482</guid>

					<description><![CDATA[<p>题目大意：给你一个数组，让你求一个范围之内所有元素的和，数组元素可以更改。 Problem: Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val. Example: [crayon-663cb30f4efc6468230719/]&#8230;</p>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/">花花酱 307. Range Sum Query &#8211; Mutable</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>题目大意：给你一个数组，让你求一个范围之内所有元素的和，数组元素可以更改。</p>
<p><strong>Problem:</strong></p>
<p>Given an integer array <i>nums</i>, find the sum of the elements between indices <i>i</i> and <i>j</i> (<i>i</i> ≤ <i>j</i>), inclusive.</p>
<p>The <i>update(i, val)</i> function modifies <i>nums</i> by updating the element at index <i>i</i> to <i>val</i>.</p>
<p><b>Example:</b></p>
<pre class="crayon-plain-tag">Given nums = [1, 3, 5]

sumRange(0, 2) -&gt; 9
update(1, 2)
sumRange(0, 2) -&gt; 8</pre>
<p><b>Note:</b></p>
<ol>
<li>The array is only modifiable by the <i>update</i> function.</li>
<li>You may assume the number of calls to <i>update</i> and <i>sumRange</i> function is distributed evenly.</li>
</ol>
<p><strong>Idea:</strong></p>
<p>Fenwick Tree</p>
<p><strong>Solution:</strong></p>
<p>C++</p>
<p>Time complexity:</p>
<p>init O(nlogn)</p>
<p>query: O(logn)</p>
<p>update: O(logn)<br /><div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">
</p>
<pre class="crayon-plain-tag">// Author: Huahua
// Running time: 83 ms
class FenwickTree {    
public:
    FenwickTree(int n): sums_(n + 1, 0) {}
    
    void update(int i, int delta) {
        while (i &lt; sums_.size()) {
            sums_[i] += delta;
            i += lowbit(i);
        }
    }
    
    int query(int i) const {        
        int sum = 0;
        while (i &gt; 0) {
            sum += sums_[i];
            i -= lowbit(i);
        }
        return sum;
    }
private:
    static inline int lowbit(int x) { return x &amp; (-x); }
    vector&lt;int&gt; sums_;
};

class NumArray {
public:
    NumArray(vector&lt;int&gt; nums): nums_(std::move(nums)), tree_(nums_.size()) {
        for (int i = 0; i &lt; nums_.size(); ++i)
            tree_.update(i + 1, nums_[i]);
    }
    
    void update(int i, int val) {
        tree_.update(i + 1, val - nums_[i]);
        nums_[i] = val;
    }
    
    int sumRange(int i, int j) {
        return tree_.query(j + 1) - tree_.query(i);
    }
private:
    vector&lt;int&gt; nums_;
    FenwickTree tree_;
};</pre>

</div><h2 class="tabtitle">Java</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua
// Running time: 130 ms
class NumArray {
    FenwickTree tree_;
    int[] nums_;
    public NumArray(int[] nums) {
        nums_ = nums;
        tree_ = new FenwickTree(nums.length);
        for (int i = 0; i &lt; nums.length; ++i)
            tree_.update(i + 1, nums[i]);
    }
    
    public void update(int i, int val) {
        tree_.update(i + 1, val - nums_[i]);
        nums_[i] = val;
    }
    
    public int sumRange(int i, int j) {
        return tree_.query(j + 1) - tree_.query(i);
    }
class FenwickTree {
    int sums_[];
    public FenwickTree(int n) {
        sums_ = new int[n + 1];
    }
    
    public void update(int i, int delta) {
        while (i &lt; sums_.length) {
            sums_[i] += delta;
            i += i &amp; -i;
        }
    }
    
    public int query(int i) {
        int sum = 0;
        while (i &gt; 0) {
            sum += sums_[i];
            i -= i &amp; -i;
        }
        return sum;
    }
}
}</pre>

</div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">"""
Author: Huahua
Running time: 192 ms (&lt; 90.00%)
"""
class FenwickTree:
    def __init__(self, n):
        self._sums = [0 for _ in range(n + 1)]
        
    def update(self, i, delta):
        while i &lt; len(self._sums):
            self._sums[i] += delta
            i += i &amp; -i
    
    def query(self, i):
        s = 0
        while i &gt; 0:
            s += self._sums[i]
            i -= i &amp; -i
        return s
    
class NumArray:

    def __init__(self, nums):
        self._nums = nums
        self._tree = FenwickTree(len(nums))
        for i in range(len(nums)):
            self._tree.update(i + 1, nums[i])

    def update(self, i, val):
        self._tree.update(i + 1, val - self._nums[i])
        self._nums[i] = val
        

    def sumRange(self, i, j):
        return self._tree.query(j + 1) - self._tree.query(i)</pre>
</div></div>


<h2>Solution 2: Segment Tree</h2>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="crayon-plain-tag">// Author: Huahua, running time: 24 ms
class SegmentTreeNode {
public:
  SegmentTreeNode(int start, int end, int sum,
                  SegmentTreeNode* left = nullptr,
                  SegmentTreeNode* right = nullptr): 
    start(start),
    end(end),
    sum(sum),
    left(left),
    right(right){}      
  SegmentTreeNode(const SegmentTreeNode&amp;) = delete;
  SegmentTreeNode&amp; operator=(const SegmentTreeNode&amp;) = delete;
  ~SegmentTreeNode() {
    delete left;
    delete right;
    left = right = nullptr;
  }
  
  int start;
  int end;
  int sum;
  SegmentTreeNode* left;
  SegmentTreeNode* right;
};

class NumArray {
public:
  NumArray(vector&lt;int&gt; nums) {
    nums_.swap(nums);
    if (!nums_.empty())
      root_.reset(buildTree(0, nums_.size() - 1));
  }

  void update(int i, int val) {
    updateTree(root_.get(), i, val);
  }

  int sumRange(int i, int j) {
    return sumRange(root_.get(), i, j);
  }
private:
  vector&lt;int&gt; nums_;
  std::unique_ptr&lt;SegmentTreeNode&gt; root_;
  
  SegmentTreeNode* buildTree(int start, int end) {  
    if (start == end) {      
      return new SegmentTreeNode(start, end, nums_[start]);
    }
    int mid = start + (end - start) / 2;
    auto left = buildTree(start, mid);
    auto right = buildTree(mid + 1, end);
    auto node = new SegmentTreeNode(start, end, left-&gt;sum + right-&gt;sum, left, right);    
    return node;
  }
  
  void updateTree(SegmentTreeNode* root, int i, int val) {
    if (root-&gt;start == i &amp;&amp; root-&gt;end == i) {
      root-&gt;sum = val;
      return;
    }
    int mid = root-&gt;start + (root-&gt;end - root-&gt;start) / 2;
    if (i &lt;= mid) {
      updateTree(root-&gt;left, i, val);
    } else {      
      updateTree(root-&gt;right, i, val);
    }
    root-&gt;sum = root-&gt;left-&gt;sum + root-&gt;right-&gt;sum;
  }
  
  int sumRange(SegmentTreeNode* root, int i, int j) {    
    if (i == root-&gt;start &amp;&amp; j == root-&gt;end) {
      return root-&gt;sum;
    }
    int mid = root-&gt;start + (root-&gt;end - root-&gt;start) / 2;
    if (j &lt;= mid) {
      return sumRange(root-&gt;left, i, j);
    } else if (i &gt; mid) {
      return sumRange(root-&gt;right, i, j);
    } else {
      return sumRange(root-&gt;left, i, mid) + sumRange(root-&gt;right, mid + 1, j);
    }
  }
};</pre>
</div></div>
<p>The post <a rel="nofollow" href="https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/">花花酱 307. Range Sum Query &#8211; Mutable</a> appeared first on <a rel="nofollow" href="https://zxi.mytechroad.com/blog">Huahua&#039;s Tech Road</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/data-structure/307-range-sum-query-mutable/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
