• 线段树基础总结


    线段树几个基本操作

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

    主要思想:

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

    一个特殊的模块:

    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 }
  • 相关阅读:
    python 并发编程 多线程 event
    python 并发编程 多线程 定时器
    python 并发编程 多线程 信号量
    linux top 查看CPU命令
    python 并发编程 多线程 GIL与多线程
    python 并发编程 多线程 死锁现象与递归锁
    python 并发编程 多线程 GIL与Lock
    python GIL全局解释器锁与互斥锁 目录
    python 并发编程 多线程 GIL全局解释器锁基本概念
    执行python程序 出现三部曲
  • 原文地址:https://www.cnblogs.com/daybreaking/p/9427464.html
Copyright © 2020-2023  润新知