线段树-区间求和-动态开点-Node版本

 1 #include <bits/stdc++.h>
 2 #include <unordered_map>
 3 using namespace  std;
 4 //线段树成,node版本;
 5 class Node{
 6 public:
 7     Node * left;
 8     Node * right;
 9     int val;
10     //懒惰标记
11     int add;
12     Node():left(nullptr),right(nullptr),val(0),add(0){};
13 };
14 class SegmentTree{
15 private:
16     Node  * node;
17     int N = 1e9;
18 public:
19     //如果给了arr的具体范围,start,end;建树;
20     void buildtree(Node * node,int start,int end,vector<int> arr){
21         //抵达叶子结点
22         if(start == end){
23             node->val = arr[start];
24             return;
25         }
26         int mid = start+(end-start)/2;
27         buildtree(node->left,start,mid,arr);
28         buildtree(node->right,mid+1,end,arr);
29         //后序位置
30         node->val = node->left->val + node->right->val;
31     }
32     //如果没有给arr,不知道具体范围,只有数据的取值范围,且很大,使用动态开点的方法;
33     //什么是动态开点,就是一开始不建树,而是在【查询】和【更新】的时候,进行结点的建立。
34 
35     //【更新】,我们如果要更新【2-4】,则只更新【2-2】和【3-4】;对于【3-3】【4-4】是通过懒惰标记下推来更新的;
36     //更新,node是头结点,stanr,end是总的区间范围,left,right是需要修改的区间范围,val是该区间需要加上的值(+1,/或减-1)
37     void update(Node * node,int start,int end,int left,int right,int val){
38         //找到了要更新的区间
39         if(left <= start && end <= right){
40             //node的值更新来自下面所有子树的更新之和;
41             node->val += ((end-start)+1)*val;
42             //增加懒惰标记
43             node->add = val;
44             return;
45         }
46         //没找到满足的区间,继续向下找
47         int mid = start+(end-start)/2;
48         //下推标记
49         pushDown(node,mid-start+1,end-mid);
50         //递归
51         if(left <= mid) update(node->left,start,mid,left,right,val);
52         if(mid < right) update(node->right,mid+1,end,left,right,val);
53         //后序位置
54         node->val = node->left->val + node->right->val;
55     }
56 
57     //懒惰标记下推,node是传入的结点,leftNum是左叶子结点数的个数,rightNum是右叶子结点数的个数
58     void pushDown(Node * node,int leftNum,int rightNum) {
59         //动态开点
60         if (node->left == nullptr) node->left = new Node();
61         if (node->right == nullptr) node->right = new Node();
62         //如果node没有懒惰标记,不用下推了
63         if (node->add == 0) return;
64         //否则,更新值
65         node->left->val += node->add * leftNum;
66         node->right->val += node->add * rightNum;
67         //add下推
68         node->left->add = node->add;
69         node->right->add = node->add;
70         //取消当前结点的标记
71         node->add = 0;
72     }
73 
74     //查询,在satrt,end范围里查询left,right区间的结果,node表示的范围是【start,end】的值;
75     int query(Node * node,int start,int end,int  left,int right){
76         //找到了要查询的区间
77         if(left <= start && end <= right){
78             return node->val;
79         }
80         //往下找
81         int mid = start + (end-start)/2;
82         int ans = 0;
83         //标记下推
84         pushDown(node,mid-start+1,end-mid);
85         if(left <= mid) ans += query(node->left,start,mid,left,right);
86         if(mid < right) ans += query(node->right,mid+1,end,left,right);
87         return ans;
88     }
89 };
90 int main(){
91 
92 }

 

posted @ 2022-06-20 14:14  coyote25  阅读(45)  评论(0编辑  收藏  举报