• 神奇线段树模板+练习


    看到hjw初一神线段树辣么6,于是默默又去复(xue)习(xi)了一下线段树。

    线段树大概的原理什么的就不讲了。放个模板就好。(可能注释会比较多)

    我线段树有个风格... 先说下   i<<1 的意思是 i*2  

                                         (i<<1) or 1 的意思是 i*2+1

    注释有错麻烦说下~~~

    type
       node=record
            l,r:longint;//节点区间[l,r]
            sum:int64;//节点的信息,这里指和
            flag:longint;//懒惰标记
       end;
    var
        tree:array[0..800000]of node;//线段树
        ans:int64;//答案
        i:longint;
        x,d,a,b,p:longint;
        n,m:longint;
    procedure changesum(i:longint);//上推过程更改节点的信息
    begin
      tree[i].sum:=tree[i<<1].sum+tree[i<<1 or 1].sum;
    end;
    
    procedure build(i:longint;l,r:longint);//建树,以节点i为根,l,r是总区间
    var m:longint;//二分思想的中间值
    begin
      tree[i].l:=l;
      tree[i].r:=r;
      if tree[i].l=tree[i].r then  //到达叶子节点,可以回溯了
      begin
        exit;
      end;
      m:=(l+r)>>1;//中间值
      build(i << 1,l,m); //向左儿子建树
      build((i << 1) or 1,m+1,r);//向右儿子建树
      changesum(i);//回溯更改节点信息
    end;
    
    procedure down(i:longint);//下推
    var l,r,lnum,rnum:longint;
    begin
      l:=i<<1; //左儿子
      r:=i<<1 or 1; //右儿子
      lnum:=tree[l].r-tree[l].l +1; //左儿子包含的数的个数
      rnum:=tree[r].r-tree[r].l +1; //右儿子包含的数的个数
      inc(tree[l].flag,tree[i].flag); //向左儿子下推懒惰标记
      inc(tree[r].flag,tree[i].flag); //向右儿子下推懒惰标记
      inc(tree[l].sum,tree[i].flag*lnum); //更新左儿子信息
      inc(tree[r].sum,tree[i].flag*rnum); //更新右儿子信息
      tree[i].flag :=0; //懒惰标记清零
    end;
    
    procedure aski(i:longint;x:longint); //单点查询, i 为当前节点, x 为查询的下标, 
    var m:longint;
    begin
      if tree[i].l=tree[i].r then //到叶子节点,可以返回值
      begin
        ans:=tree[i].sum; //储存在 ans(全局变量) 中
        exit;
      end;
      if tree[i].flag<>0 then down(i); //有懒惰标记要下推
      m:=(tree[i].l+tree[i].r)>>1; //中间值
      if x<=m then aski(i<<1,x) else aski(i<<1 or 1,x); //二分查找 x
    end;
    
    procedure changei(i,d,x:longint); //单点修改, i 为当前节点, d 为修改值, x 为修改的下标
    var m:longint;
    begin
      if tree[i].l=tree[i].r then //到叶子节点,可以修改了
      begin
        inc(tree[i].sum,d);
        exit;
      end;
      m:=(tree[i].l+tree[i].r)>>1;
      if x<=m then changei(i<<1,d,x) else changei(i<<1 or 1,d,x); //查找 x 节点
      changesum(i); //回溯更改节点信息
    end;
    
    procedure asklr(i:longint;a,b:longint); //查询区间 i 为当前节点 a,b 为查询的[l,r]区间
    var m:longint;
    begin
      if (tree[i].l>=a)and(tree[i].r<=b) then //有一个节点的区间能包含[l,r](这里的 a,b )区间
      begin
        inc(ans,tree[i].sum);
        exit;
      end;
      if tree[i].flag<>0 then down(i); //下推咯
      m:=(tree[i].l+tree[i].r)>>1;
      if a<=m then asklr(i<<1,a,b);
      if b>m then asklr(i<<1 or 1,a,b);
    end;
    
    procedure changelr(i,a,b,d:longint); //更改区间  i为当前节点   a 为 l   b 为 r   d 为修改值
    var m:longint;
    begin
      if (tree[i].l>=a)and(tree[i].r<=b) then
      begin
        inc(tree[i].sum,(tree[i].r-tree[i].l+1)*d);
        inc(tree[i].flag,d); //记得懒惰标记咯
        exit;
      end;
      if tree[i].flag<>0 then down(i); //下推咯
      m:=(tree[i].l+tree[i].r)>>1;
      if a<=m then changelr(i<<1,a,b,d);
      if b>m then changelr(i<<1 or 1,a,b,d);
      changesum(i);
    end;
    
    begin
      build(1,1,n); // 以1为根,  [l,r]区间就是[1,n]
    aski(1,x); // 从根节点 1 开始找, 查询为 x 下标的信息
    changei(1,d,x); //从根节点 1 开始找, 修改值为 d , 修改 x 下标
    asklr(1,l,r); //从根节点 1 开始找, 查询 l,r 区间
    changelr(1,l,r,d) //从根节点 1 开始找 修改 l,r 区间 修改值d
    end.

    练习什么的以后再来。

  • 相关阅读:
    “朋友圈”又添好友,DataPipeline与统信服务器操作系统完成产品互认证
    DataPipeline与飞腾完成产品兼容性互认证,携手共建自主IT底层生态
    「山东城商行联盟」数据库准实时数据采集系统上线,DataPipeline助力城市商业银行加快数字化转型
    DataPipeline 实时数据融合产品入驻青云云市场,催化企业数据价值释放
    2020年净利暴涨1288%,遨森电商携手DataPipeline构建实时数据融合体系跑出加速度!
    宏昆酒店集团携手DataPipeline打造实时数据融合平台,酒店业精益管理的新秘诀
    销售易携手DataPipeline,推动“实时感知主动决策客户成功”的变革!
    DataPipeline助力悠星网络出海,以实时数据管理护航爆款游戏
    FIGR/IR业务流程
    ABAP调用堆栈
  • 原文地址:https://www.cnblogs.com/Bunnycxk/p/6501861.html
Copyright © 2020-2023  润新知