1
+ // 如果使用常规操作,查询和更新两个操作一个是on的复杂度,另外一个是o1的复杂度,但是如果使用
2
+ // 区间树,就可以将两个操作都变成logn的复杂度
3
+
4
+ // Runtime: 32 ms, faster than 91.34% of C++ online submissions for Range Sum Query - Mutable.
5
+ // Memory Usage: 19.7 MB, less than 8.33% of C++ online submissions for Range Sum Query - Mutable.
6
+
7
+ struct cell
8
+ {
9
+ cell () : start(-1 ), end(-1 ), sum(0 ) {}
10
+ int start, end;
11
+ int sum;
12
+ };
13
+
14
+ class NumArray
15
+ {
16
+ public:
17
+
18
+ // 构建区间树
19
+ NumArray (vector<int >& nums)
20
+ {
21
+ // 边界条件处理
22
+ if (nums.size () == 0 ) return ;
23
+
24
+ // 计算数组的大小
25
+ int rightPtr = nums.size () - 1 , layer = 1 ;
26
+ while (rightPtr)
27
+ rightPtr /= 2 , ++layer;
28
+
29
+ // 在定义默认构造函数后,这样做之后每个新添加上的元素会按照默认构造进行初始化
30
+ tree.resize (pow (2 , layer) - 1 );
31
+
32
+ // 建立线段树
33
+ buildSegmentTree (0 , nums.size () - 1 , 0 , nums);
34
+ }
35
+
36
+ // 更新区间树中的元素 logn的时间复杂度
37
+ void update (int i, int val)
38
+ {
39
+ if (tree.size () != 0 )
40
+ {
41
+ int start = 0 , end = tree.front ().end ;
42
+ int index = 0 ;
43
+
44
+ // dfs查找
45
+ while (start != end)
46
+ {
47
+ int mid = (start + end) / 2 ;
48
+ if (mid >= i)
49
+ end = mid, index = index * 2 + 1 ;
50
+ else
51
+ start = mid + 1 , index = index * 2 + 2 ;
52
+ }
53
+
54
+ int offset = val - tree[index].sum ;
55
+
56
+ // 回溯整个路径
57
+ while (true )
58
+ {
59
+ tree[index].sum += offset;
60
+ if (index == 0 ) break ;
61
+
62
+ if (index & 1 ) index = index / 2 ; // 奇数节点
63
+ else index = index / 2 - 1 ; // 偶数节点
64
+ }
65
+ }
66
+ }
67
+
68
+ // 查询函数 同样是logn的时间复杂度
69
+ int sumRange (int start, int end)
70
+ {
71
+ return (tree.size () != 0 && start <= end && start >= 0 ) ? query (start, end, 0 ) : 0 ;
72
+ }
73
+
74
+ private:
75
+ vector<cell> tree;
76
+ private:
77
+ int query (int start, int end, int index)
78
+ {
79
+ int mid = (tree[index].start + tree[index].end ) / 2 ;
80
+
81
+ if (start == tree[index].start && end == tree[index].end )
82
+ return tree[index].sum ;
83
+ else if (end <= mid)
84
+ return query (start, end, 2 * index + 1 );
85
+ else if (start > mid)
86
+ return query (start, end, 2 * index + 2 );
87
+ else
88
+ return query (start, mid, 2 * index + 1 ) + query (mid + 1 , end, 2 * index + 2 );
89
+ }
90
+
91
+ int buildSegmentTree (int start, int end, int index, const vector<int >& nums)
92
+ {
93
+ if (start == end)
94
+ {
95
+ tree[index].start = start;
96
+ tree[index].end = start;
97
+ tree[index].sum = nums[start];
98
+ }
99
+ else
100
+ {
101
+ int mid = (start + end) / 2 ;
102
+ int leftSum = buildSegmentTree (start, mid, 2 * index + 1 , nums);
103
+ int rightSum = buildSegmentTree (mid + 1 , end, 2 * index + 2 , nums);
104
+
105
+ tree[index].start = start;
106
+ tree[index].end = end;
107
+ tree[index].sum = leftSum + rightSum;
108
+ }
109
+ return tree[index].sum ;
110
+ }
111
+ };
0 commit comments