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 }

 

posted @ 2017-08-04 01:14  GGBeng  阅读(153)  评论(0编辑  收藏  举报