线段树-区间求和-动态开点-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 }