• 线段树模版


    线段树的节点类型

    1 const int maxn = 1e5;
    2 typedef struct Node {
    3     int left;       //节点所维护区间的左边界
    4     int right;      //节点所维护区间的右边界
    5     int data;       //节点的数据
    6     int lazy;       //节点的懒惰标记
    7 }node[maxn<<2];

    构建线段树

     1 void build(int root,int left,int right) {
     2     node[root].left = left;
     3     node[root].right = right;
     4     if(left == right) {
     5         node[root].Max = num[left];
     6         return;
     7     }
     8     int mid = (left+right)>>1;
     9     build(root<<1,left,mid);
    10     build(root<<1|1,mid+1,right);
    11     push_up(root);   ///更新当前节点的函数。
    12 }

    单点更新操作代码

     1 //单点更新操作,把原来数组中的pos位置上的数字更新成value。
     2 void update(int pos,int value,int root) {
     3     //是叶子节点
     4     if(node[root].left == node[root].right) {
     5         node[root].Max = value;   //更新对应节点的值返回
     6         return;
     7     }
     8     int mid = (left+right)>>1;
     9     if(pos <= mid) update(pos,value,root<<1);   //节点位于左区间
    10     else update(pos,value,root<<1|1);           //节点位于右区间
    11     push_up(root);                              //子节点更新后,更新父节点。
    12 }

    区间查询:两种方法:1.区间覆盖2.区间相等

    详情见https://www.bilibili.com/video/BV1kZ4y127HP?spm_id_from=333.337.search-card.all.click

     1 //区间查询 
     2 LL query1(int k, int l, int r) //方法1:区间覆盖 
     3 {
     4     if(tr[k].l>=l && tr[k].r<=r)
     5     {
     6         return tr[k].da;
     7     } 
     8     int mid=(tr[k].l+tr[k].r)/2;
     9     int ret=0;
    10     if(l<=mid)
    11         ret+=query1(lc, l, r);
    12     if(r>=mid+1)
    13         ret+=query1(rc, l, r);
    14     return ret;
    15 }
    16 LL query2(int k, int l, int r) //方法2:区间相等 
    17 {
    18     if(tr[k].l==l && tr[k].r==r)
    19         return tr[k].da;
    20     int mid=(tr[k].l+tr[k].r)/2;
    21     int ret=0;
    22     if(r<=mid)
    23         ret+=query2(lc, l, r);
    24     else if(l>mid)
    25         ret+=query2(rc, l, r);
    26     else
    27         ret+=query2(lc, l, mid)+query2(rc, mid+1, r);
    28     return ret;    
    29 }

    区间更新代码:

     1 //更新当前节点
     2 void push_up(int root) {
     3     node[root].sum = node[root<<1].sum + node[root<<1|1].sum;
     4 } 
     5 //下推标记
     6 void push_down(int root) {
     7     //说明该节点有标记
     8     if(node[root].lazy>0) {
     9         //求左区间的长度
    10         int leftLen = node[root<<1].right - node[root<<1].left + 1;
    11         //求右区间的长度
    12         int rightLen = node[root<<1|1].right - node[root<<1|1].left + 1;
    13         //更新左区间和值
    14         node[root<<1].sum += leftLen*node[root].lazy;
    15         //更新右区间和值
    16         node[root<<1|1].sum += rightLen*node[root].lazy;
    17         //下推标记到左区间
    18         node[root<<1].lazy += node[root].lazy;
    19         //下推标记到右区间
    20         node[root<<1|1].lazy += node[root].lazy;
    21         //当前节点标记下推完毕,恢复成无标记状态
    22         node[root].lazy = 0; 
    23     }
    24 }
    25 //将区[L,R]中的数字都加上add
    26 void update(int L,int R,int add,int root) {
    27     //到达子区间,更新该区间的值,并留下标记
    28     if(L<=node[root],left && node[root].right<=R) {
    29         node[root].sum += (node[root].right-node[root].left+1)*add;
    30         node[root].lazy += add;
    31         return;
    32     }
    33     push_down(root);    //下推之前残留的标记
    34     int mid = (node[root].left+node[root].right)/2;
    35     if(L<=mid) update(L,R,add,root<<1);    //更新左区间
    36     if(R>mid) update(L,R,add,root<<1|1);   //更新右区间
    37     push_up(root);   //更新当前节点
    38 }

    详见https://blog.csdn.net/wyxeainn/article/details/79239630

  • 相关阅读:
    滑动切换界面---多个Activity
    172. Factorial Trailing Zeroes
    152. Maximum Product Subarray
    149. Max Points on a Line
    [转载][c++]用宏(Macro)定义一个函数
    [转载][C++]C++11 左值、右值、右值引用详解
    [转载][c++]C++中指针常量和常量指针的区别
    [转载][C++]类构造函数初始化列表
    22. Generate Parentheses
    328. Odd Even Linked List
  • 原文地址:https://www.cnblogs.com/tflsnoi/p/16136173.html
Copyright © 2020-2023  润新知