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 }