线段树 及其操作(转载)

文章非博主原创

原出处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);
    }
posted @ 2019-06-28 10:36  liuzitong本体  阅读(182)  评论(0编辑  收藏  举报