zoukankan      html  css  js  c++  java
  • 线段树基础总结

    线段树几个基本操作

    • 单点查询
    • 单点修改
    • 区间查询
    • 区间修改
    • 区间求最大值

    主要思想:

    将一个线性的一维数组构建成树形的数组,使得可以用二分的思想来进行区间操作,降低时间复杂度,但是多占用了空间,典型的用空间换时间。

    一个特殊的模块:

    lazy数组,考虑到对区间的操作有很多次,并且没有必要每一次对区间的操作都更新到点,只需要在需要的时候更新点就可以了。所以用lazy数组来标记一下对该区间里的数进行的操作。

    线段树架构:

    • 递归建树便于更新
    • 递归操作同样便于更新

    解释代码(以线段树求区间最大值为例,顺便说一下区间求和):

    HDU - 1754 

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<stack>
      8 #include<deque>
      9 #include<map>
     10 #include<iostream>
     11 using namespace std;
     12 typedef long long  LL;
     13 const double pi=acos(-1.0);
     14 const double e=exp(1);
     15 //const int MAXN =2e5+10;
     16 const int N = 200010*4;
     17 
     18 #define lson i << 1,l,m
     19 #define rson i << 1 | 1,m + 1,r
     20 typedef struct Node
     21 {
     22     LL l;
     23     LL r;
     24     LL mid()
     25     {
     26         return (l+r)/2;
     27     }
     28 } Node;
     29 
     30 LL ans;
     31 Node node[N];
     32 LL add[N];
     33 LL sum[N];
     34 
     35 
     36 //void PushUp(LL i)
     37 //{
     38 //    sum[i]=sum[i<<1]+sum[i<<1 | 1];    //对左右子树进行求和
     39 //}
     40 void PushUp(LL i)
     41 {
     42     sum[i]=max(sum[i<<1],sum[i<<1 | 1]);    //找左右子树的最大值
     43 }
     44 
     45 void build(LL i,LL l,LL r)  
     46 {
     47     node[i].l=l;        //这几行是递,在这个过程中初始化、赋初值
     48     node[i].r=r;
     49     sum[i]=0;
     50     add[i]=0;
     51     if(l==r)
     52     {
     53         scanf("%lld",&sum[i]);      //到达了最后一层的叶子节点,开始取数
     54         return ;
     55     }
     56 
     57     LL m=node[i].mid();     //判断建进左子树还是右子树
     58     build(lson);            
     59     build(rson);
     60     PushUp(i);          //归的过程,对区间进行更新
     61 }
     62 
     63 void PushDown(LL i,LL L)        //add[i]代表的是对区间中的每一个数应该进行的操作,所以他的子节点应该和他一样,且子节点的值应当是区间中数的个数乘以每个数的改变值
     64 {
     65     if(add[i])
     66     {
     67         add[i << 1]+=add[i];
     68         add[i<< 1 | 1]+=add[i];
     69         sum[i << 1]+=add[i]*(L-(L >> 1));
     70         sum[i << 1 | 1]+=add[i]*(L >> 1);
     71         add[i]=0;
     72     }
     73 }
     74 
     75 void line_update(LL v,LL l,LL r,LL i)
     76 {
     77     if(node[i].l==l&&node[i].r==r)      //找到了那个区间(点),进行更新
     78     {
     79         sum[i]+=v*(r-l+1);
     80         add[i]+=v;
     81         return ;
     82     }
     83     //PushDown(i,node[i].r-node[i].l+1);
     84     LL m=node[i].mid();
     85     if(r<=m)
     86         line_update(v,l,r,i <<1);
     87     else
     88     {
     89         if(l>m)
     90             line_update(v,l,r,i<<1 | 1);
     91         else
     92         {
     93             line_update(v,l,m,i << 1);
     94             line_update(v,m+1,r,i << 1 | 1);
     95         }
     96     }
     97     PushUp(i);      //因为点被更新过了,所以要对与他有关都更新
     98 }
     99 
    100 LL query(LL l,LL r,LL i)
    101 {
    102     if(node[i].l==l&&node[i].r==r)
    103     {
    104         return sum[i];
    105     }
    106     PushDown(i,node[i].r-node[i].l+1);
    107     LL m=node[i].mid();
    108     LL ans=0;        //确保最大值是要求区间的
    109     if(r<=m)
    110         ans=max(query(l,r,i << 1),ans);         
    111     else
    112     {
    113         if(l>m)
    114             ans=max(query(l,r,i << 1 | 1),ans);
    115         else
    116         {
    117             ans=max(query(l,m,i << 1),ans);
    118             ans=max(query(m+1,r,i << 1 | 1),ans);
    119         }
    120     }
    121     return ans;
    122  //   ans=max(ans,sum[i]);
    123 }
    124 
    125 void spot_update(LL v,LL l,LL r,LL i)
    126 {
    127     if(node[i].l==l&&node[i].r==r)
    128     {
    129         sum[i]=v;
    130         return ;
    131     }
    132     LL m=node[i].mid();
    133     if(r<=m)
    134         spot_update(v,l,r,i << 1);
    135     else
    136     {
    137         if(l>m)
    138             spot_update(v,l,r,i << 1 | 1);
    139         else
    140         {
    141             spot_update(v,l,m,i << 1);
    142             spot_update(v,m+1,r,i << 1 | 1);
    143         }
    144     }
    145     PushUp(i);
    146 }
    147 
    148 int main()
    149 {
    150     LL n,q,i,p,j,t,m;
    151     LL a,b,c;
    152     char cc;
    153 
    154     while(scanf("%lld%lld",&n,&m)!=EOF)
    155     {
    156         build(1,1,n);
    157         while(m--)
    158         {
    159             scanf(" %c",&cc);
    160 
    161             if(cc=='Q')
    162             {
    163                 ans=0;
    164                 scanf("%lld%lld",&a,&b);
    165                 printf("%lld
    ",query(a,b,1));
    166             }
    167             else if(cc=='U')
    168             {
    169                 scanf("%lld%lld",&a,&b);
    170                 spot_update(b,a,a,1);
    171 
    172             }
    173             getchar();
    174         }
    175     }
    176 
    177 //        else if(cc==-1)
    178 //        {
    179 //            scanf("%lld%lld%lld",&a,&b,&c); //给区间[a,b]+c
    180 //            line_update(c,a,b,1);
    181 //        }
    182 
    183     return 0;
    184 }
  • 相关阅读:
    caffe绘制训练过程的loss和accuracy曲线
    ROC曲线和PR曲线
    Lintcode--009(单词切分)
    已知有字符串foo=”get-element-by-id”,写一个function将其转化成驼峰表示法”getElementById”
    web前端性能优化汇总
    Restful风格的前后端分离
    渐进式 JPEG (Progressive JPEG)来提升用户体验
    ESLint检测JavaScript代码
    JavaScript对象浅复制
    JavaScript对象深复制
  • 原文地址:https://www.cnblogs.com/daybreaking/p/9427464.html
Copyright © 2011-2022 走看看