zoukankan      html  css  js  c++  java
  • 线段树 及其操作(转载)

    文章非博主原创

    原出处https://tjor.blog.luogu.org/xian-duan-shu-yu-shu-zhuang-shuo-zu

    概念

    线段树

    线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

    使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。

    比如讲一个有4个数的线段树,是长这个样子的:

    一号节点,代表着区间1~4

    二号节点,代表区间1~2

    三号节点,代表区间3~4

    以此类推。。。。。。

    很容易发现,对于n号节点来说,n×2代表着它的区间的前半段,n×2+1代表着它的区间的后半段。

    线段树构造

    就是用到递归:先设left=1,right=n,然后每一次递归,left、mid和mid+1、right。代码如下:

        void build(int left,int right,int index)
        {
            tree[index].left=left;
            tree[index].right=right;
               if(left==right)
                return ;
            int mid=(right+left)/2;
            build(left,mid,index*2);
            build(mid+1,right,index*2+1);
        }
    

    线段树单点查询

    就是从根节点,一直搜索到目标节点,然后一路上都加上就好了。

        void search(int index,int dis)
        {
            ans+=tree[index].num;
            if(tree[index].left==tree[index].right)
                return ;
            if(dis<=tree[index*2].right)
                search(index*2,dis);
            if(dis>=tree[index*2+1].left)
                search(index*2+1,dis);
        }
    

    线段树单点修改

    单点修改就是每到一个节点,看这个节点代表着的区间包括不包括这个点,包括就加上。

        void my_plus(int index,int dis,int k)
        {
            tree[index].num+=k;
            if(tree[index].left==tree[index].right)
                return ;
            if(dis<=tree[index*2].right)
                my_plus(index*2,dis,k);
            if(dis>=tree[index*2+1].left)
                my_plus(index*2+1,dis,k);
        } 
    

    线段树区间查询

    区间查询就是,每查到一个区间,有三种选择:
    
    1、如果这个区间被完全包括在目标区间内,那么加上这个区间的和,然后return;
    
    2、如果这个区间的right>目标区间的left,那么查询这个区间;
    
    3、如果这个区间的left<目标区间的right,也查询这个区间;
    
        void search(int index,int l,int r)
        {
            if(tree[index].left>=l && tree[index].right<=r)
            {
                ans+=tree[index].num;
                return ;
            }
            if(tree[index*2].right>=l)
                search(index*2,l,r);
            if(tree[index*2+1].left<=r)
                search(index*2+1,l,r);
        }
    

    线段树区间修改

    和线段树区间查询类似,分为三种
    
    1、如果当前区间完全属于要加的区间,那么这个区间,也就是节点加上,然后return;
    
    2、如果这个区间的right>目标区间的left,那么查询这个区间;
    
    3、如果这个区间的left<目标区间的right,也查询这个区间;
    
        void pls(int index,int l,int r,int k)
        {
            if(tree[index].left>=l && tree[index].right<=r)
            {
                tree[index].num+=k;
                return ;
            }
            if(tree[index*2].right>=l)
               pls(index*2,l,r,k);
            if(tree[index*2+1].left<=r)
               pls(index*2+1,l,r,k);
        }
    
  • 相关阅读:
    Python数组/切片
    ArcGISEngine 版本升级的方法
    c# 使用类名称访问成员变量
    向模拟器里添加图片的简单方法
    通过self调用propery和直接调用propery的区别
    Objectivec 使用构造函数来初始化函数并调用函数的方法
    IPhone模拟器截取当前活动窗体,并保存为图片
    Windows Server2008 安装Oracle失败
    ALL、DISTINCT、DISTINCTROW、TOP 谓词
    ObjectiveC 语法快速参考
  • 原文地址:https://www.cnblogs.com/lztzs/p/11101382.html
Copyright © 2011-2022 走看看