zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    图片完全填充CardView区域
    调用系统相机拍照并展示
    Android开发之加载GIF图片
    使用SatelliteMenu创建动画菜单
    swift中简单KVC和KVO的使用
    swift GCD的简单使用
    swift协议的使用方法和注意事项
    swift找window,导航栏的简单使用,Controller通过闭包传值简单示例
    swift中闭包的使用
    swift中UIButton的使用
  • 原文地址:https://www.cnblogs.com/xzxl/p/7282884.html
Copyright © 2011-2022 走看看