zoukankan      html  css  js  c++  java
  • 线段树

    在清北学堂的时候,老师讲了一下,没太搞懂,回来自己理解了一下

    *******线段树*******


    线段树
    O(log(n))个区间覆盖L~R信息
    每层最多选两个区间

    mx区间最大值

    int n;
    int a[];
    int mx[];
    //o是当前节点编号,当前表示的区间范围
    //就是用数组实现树,mx代表o区间内最大值
    void build(int o,int l,int r){
        if(l==r){
            mx[o] = a[l];//区间内只有一个数,当然是它了
        }else{
            int mid=(l+r)/2;
            build(o*2,l,mid);//先把两个子区间的最大值求出来,再取最大
            build(o*2+1,mid+1,r);
            mx[o]=max(mx[o*2],mx[o*2+1]);
        }
    }
    build(1,1,n)//mx[1]是整个a数组里最大的


    ******分界线*******


    查询操作:
    // o结点编号,l,r线段树的区间,L,R查询的区间
    int ask(int o,int l,int r,int L,int R){
        if(l==L&&r==R){
            return mx[o];//已经找到对应区间
        }else{
        down(o);//下方标记,先不管
        int mid=(l+r)/2;
        if(R<=mid) return ask(o*2,l,mid,L,R);
        else if(L>mid)return ask(o*2+1,mid+1,r,L,R);
        else return max(ask(o*2,l,mid,L,mid),
                ask(o*2+1,mid+1,r,mid+1,R))//没有恰好对应的区间,只能将其一分为二    
        }
    }
    ask(1,1,n,L,R);


    ******分界线*******


    // 单点修改
    // l,r线段树节点表示的区间,pos修改位置(一直不变),w新的值(也不变)
    //其实这几个操作和前面差不多
    void modify(int o,int l,int r,int pos,int w){
        if(l==r){
            mx[o] = w;
        }
        else
            {
            down(o);
            int mid=(l+r)/2;
            if(pos<=mid){
                //左边
                modify(o*2,l,mid,pos,w);
            }else{
                //右边
                modify(o*2+1,mid+1,r,pos,w);
            }
            mx[o]=max(mx[o*2],mx[o*2+1]);//快速合并
        }
    }


    ******分界线*******


    // 新操作: 给位置在L~R的数字+x,直接操作没有线段树的意义
    Lazy 思想
    如果一个区间被区间修改操作整个覆盖:
    不用递归修改,建立一个lazy标记
    如果真正访问下面节点,再下放(dawn)标记
    // o, l,r表示当前区间,L,R表示要修改的区间,表示要加的值
    int lazy[];//存放标记
    void down(int o){//假如真正查询到了,才真正进行下放(但每次都需要判断)
        if(lazy[o]!=0){
            mx[o*2]+=lazy[o];
            mx[o*2+1]+=lazy[o];
            lazy[o*2]+=lazy[o];
            lazy[o*2+1]+=lazy[o];
            lazy[o]=0;   //清空标记
        }
    }
    void add(int o,int l,int r,int L,int R,int w){
        if(l==L&&r==R){
            mx[o]+=w;
            lazy[o]+=w;//对于子区间来说没有下放的标记,
        }else{
        //下放标记,貌似所以线段树的操作都有这一步
        down(o);//让子区间都加上
        int mid=(l+r)/2;
        if(R<=mid) add(o*2,l,mid,L,R,w);//左
        else if(L>mid) add(o*2+1,mid+1,r,L,R,w);//右
        else{
            add(o*2,l,mid,L,mid,w);
            add(o*2+1,mid+1,r,mid+1,R,w));
            }
        }
        mx[o]=max(mx[o*2],mx[o*2+1]);//因为子区间大小改变,mx要重新求
    }

  • 相关阅读:
    MySQL + Atlas --- 部署读写分离(实现,其他的技术有参考文档)
    基于Redis、Storm的实时数据查询实践
    Redis 配置
    Redis 安装
    redis简介
    Java-Enumeration总结
    spring源码剖析(四)自定义标签解析流程
    svn 把主干合到分支 分支合到主干
    关于Class.getResource和ClassLoader.getResource的路径问题
    instanceof, isinstance,isAssignableFrom的区别
  • 原文地址:https://www.cnblogs.com/DukeLv/p/8454504.html
Copyright © 2011-2022 走看看