線段樹 及其操做(轉載)

文章非博主原創

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

概念

線段樹

線段樹是一種二叉搜索樹,與區間樹類似,它將一個區間劃分紅一些單元區間,每一個單元區間對應線段樹中的一個葉結點。code

使用線段樹能夠快速的查找某一個節點在若干條線段中出現的次數,時間複雜度爲O(logN)。blog

好比講一個有4個數的線段樹,是長這個樣子的:
遞歸

一號節點,表明着區間1~4class

二號節點,表明區間1~2搜索

三號節點,表明區間3~4im

以此類推。。。。。。查詢

很容易發現,對於n號節點來講,n×2表明着它的區間的前半段,n×2+1表明着它的區間的後半段。img

線段樹構造

就是用到遞歸:先設left=1,right=n,而後每一次遞歸,left、mid和mid+一、right。代碼以下:di

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);
    }

線段樹區間查詢

區間查詢就是,每查到一個區間,有三種選擇:

一、若是這個區間被徹底包括在目標區間內,那麼加上這個區間的和,而後return;

二、若是這個區間的right>目標區間的left,那麼查詢這個區間;

三、若是這個區間的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);
    }

線段樹區間修改

和線段樹區間查詢相似,分爲三種

一、若是當前區間徹底屬於要加的區間,那麼這個區間,也就是節點加上,而後return;

二、若是這個區間的right>目標區間的left,那麼查詢這個區間;

三、若是這個區間的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);
    }
相關文章
相關標籤/搜索