NO1——线段树
1 /* 数组存储 */ 2 /* 预处理 */ 3 #include <iostream> 4 #include <cstdio> 5 #include <algorithm> 6 #include <climits> 7 using namespace std; 8 const int maxn = 2e5+10; 9 int arr[maxn]; //存储数据的原始数组 10 struct segTreeNode{ //节点的结构体 11 int val; //线段树节点对应的值 12 int addMark; //标记域,只在区间更新起作用 13 }; 14 segTreeNode segTree[4*maxn]; //线段树节点的空间应该为原始数据空间的4倍 15 16 /* 线段树的建立 */ 17 // 此处以求区间最大值为例 18 // root:当前线段树根节点下标 19 // [L,R]:当前数组的区间 20 void build(int root, int L, int R) 21 { 22 segTree[root].addMark = 0; //设置标记域的值 23 if(L == R){ //叶结点 24 segTree[root].val = arr[L]; //叶结点存储原始数据 25 return ; //结束此次调用 26 } 27 else{ 28 int mid = (L+R)/2; 29 build(2*root,L,mid); //递归构造左子树 30 build(2*root+1,mid+1,R); //递归构造右子树 31 //根据左右子树根节点的值,更新当前根节点的值 32 segTree[root].val = max(segTree[2*root].val, segTree[2*root+1].val); 33 } 34 } 35 36 /* 当前节点的标记域向孩子节点传递 */ 37 void pushDown(int root) 38 { 39 if(segTree[root].addMark != 0){ 40 segTree[2*root].addMark += segTree[root].addMark; //可能多次延迟标记没有向下传递,使用“+=” 41 segTree[2*root+1].addMark += segTree[root].addMark; 42 segTree[2*root].val += segTree[root].addMark; 43 segTree[2*root+1].val += segTree[root].addMark; 44 segTree[root].addMark = 0; //传递后,当前节点标记域清空 45 } 46 } 47 48 /* 区间查询函数 */ 49 // 此处以求区间最大值为例 50 // [L,R]:当前数组的区间 51 // [l,r]:查询区间 52 int query_max(int root, int L, int R, int l, int r) 53 { 54 if(l>R || r<L){ //无交集,返回一个对结果无影响的值 55 return INT_MIN; //需包含头文件<climits> 56 } 57 if(l<=L && r>=R){ //当前区间被包含进查询区间 58 return segTree[root].val; 59 } 60 pushDown(root); //标记域向下传递 61 int mid = (L+R)/2; 62 //分别从左右子树中查询,返回两者查询结果的较大值 63 return max( query_max(2*root, L, mid, l, r), query_max(2*root+1, mid+1, R, l, r) ); 64 } 65 66 /* 区间查询函数 */ 67 // 此处以求区间和为例 68 // [L,R]:当前数组的区间 69 // [l,r]:查询区间 70 int query_sum(int root, int L, int R, int l, int r) 71 { 72 if(l>R || r<L){ //无交集,返回一个对结果无影响的值 73 return 0; //0对结果无影响 74 } 75 if(l<=L && r>=R){ //当前区间被包含进查询区间 76 return segTree[root].val; 77 } 78 pushDown(root); //标记域向下传递 79 int mid = (L+R)/2; 80 //分别从左右子树中查询,将和加起来 81 int ret = 0; 82 if(l<=mid){ 83 ret += query_sum(2*root, L, mid, l, r); 84 } 85 if(r>mid){ 86 ret += query_sum(2*root+1, mid+1, R, l, r); 87 } 88 return ret; 89 } 90 91 /* 单节点的更新 */ 92 // 此处以改变节点值为例 93 // index:要更改数据在数组中的下标 94 // value:变化后的值 95 void updateNode(int root, int L, int R, int index, int value) 96 { 97 if(L == R){ //找到相应的节点 98 segTree[root].val = value; 99 return ; 100 } 101 int mid = (L+R)/2; 102 if(index <= mid){ //在左子树中更新 103 updateNode(2*root, L, mid, index, value); 104 } 105 else{ //在右子树中更新 106 updateNode(2*root+1, mid+1, R, index, value); 107 } 108 segTree[root].val = max(segTree[2*root].val, segTree[2*root+1].val); //回溯更新当前节点的值 109 } 110 111 /* 区间更新 */ 112 // 此处以增加某个值为例 113 // 此处以求区间最大值为例 114 // addVal:增加的值的大小 115 void update(int root, int L, int R, int l, int r,int addVal) 116 { 117 if(l>R || r<L){ //两区间无交集 118 return ; 119 } 120 if(l<=L && r>=R){ //查询区间包含当前区间 121 segTree[root].addMark += addVal; //标记域赋值,此后此节点的孩子都将要赋值,只不过延迟了 122 segTree[root].val += addVal; 123 return ; 124 } 125 pushDown(root); //向孩子节点传递标记值 126 int mid = (L+R)/2; 127 update(2*root, L, mid, l, r, addVal); //继续更新左子树 128 update(2*root+1, mid+1, R, l, r, addVal); //继续更新右子树 129 segTree[root].val = max(segTree[2*root].val, segTree[2*root+1].val); //由左子树和右子树的新值回溯改变它们根节点的值 130 } 131 132 /* 主函数调用 */ 133 int main() 134 { 135 int N; 136 cin>>N; 137 for(int i=1; i<=N; i++){ 138 scanf("%d",&arr[i]); 139 } 140 build(1, 1, N); //根节点为1,当前区间为[1,N] 141 return 0; 142 }