• 线段树


    线段树是一种二叉树,它的每一个节点代表一个区间[ab],它的叶节点代表单位区间[a,a],即点a

    对一个非叶节点,设它的编号为x,区间为[ab],那么它的左儿子的编号就是(2*x,区间是[a,(a+b)/2];它的右儿子的编号是(2*x+1,区间是[(a+b)/2+1,b]

     

    线段树的实现通常分为以下几个函数:

    build()//建立线段树

    update()//更新线段树(区间更新或者单点更新)

    query()//查询(区间和、区间最值)

    pushdown()//向下延时更新

    #include <iostream>
    #include <bits/stdc++.h>
    using namespace std;
    #define N 1000010
    int sum[N],a[N],lazy[N];
    void build(int l,int r,int rt)
    {
        if(l==r){
            sum[rt]=a[l];
            return;
        }
        int mid=(l+r)/2;
        build(l,mid,rt*2);//先左儿子后又儿子
        build(mid+1,r,rt*2+1);
        sum[rt]=sum[rt*2]+sum[rt*2+1];//当前区间和等于左儿子和右儿子区间和
    }
    void pushdown(int l,int r,int rt){
        if(lazy[rt]){
            lazy[rt*2]+=lazy[rt];//向下延时更新
            lazy[rt*2+1]+=lazy[rt];
            lazy[rt]=0;
            sum[rt*2]+=l*lazy[rt*2];//下面的儿子区间和也加
            sum[rt*2+1]+=r*lazy[rt*2+1];
        }
    }
    int query(int l1,int r1,int l,int r,int rt){
        if(l1<=l&&r1>=r){
            return sum[rt];
        }
        int mid=(l+r)/2;
        int ret=0;
        pushdown(mid-l+1,r-mid,rt);//更新后
        if(l1<=mid){
            ret+=query(l1,r1,l,mid,rt*2);
        }
        if(r1>mid){
            ret+=query(l1,r1,mid+1,r,rt*2+1);
        }
        return ret;
    }
    void update(int p,int v,int l,int r,int rt)//单点增加或减少
    {
        if(l==r)
        {
            sum[rt]+=v;
            return;
        }
        int mid=(l+r)/2;
        if(p<=mid){
            update(p,v,l,mid,rt*2);
        }
        if(p>mid){
            update(p,v,mid+1,r,rt*2+1);
        }
        sum[rt]=sum[rt*2]+sum[rt*2+1];
    }
    
    void update2(int l1,int r1,int v,int l,int r,int rt)//区间增加或减少
    {
        if(l1<=l&&r1>=r){
           sum[rt]+=v*(r-l+1);
           lazy[rt]+=v;//通过延时函数实现
           return;
        }
        int mid=(l+r)/2;
        if(l1<=mid){
            update2(l1,r1,v,l,mid,rt*2);
        }
        if(r1>mid){
            update2(l1,r1,v,mid+1,r,rt*2+1);
        }
        sum[rt]=sum[rt*2]+sum[rt*2+1];
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            build(1,n,1);
    
        }
        return 0;
    }

     

    注意:1.线段树要开四倍大小空间(证明可见本页备注链接)

    https://blog.csdn.net/gl486546/article/details/78243098

    2.建树复杂度为o(nlogn)每次更新、询问的复杂度均为o(logn)

    (最坏情况是从根节点一直更新到叶子节点)

     

  • 相关阅读:
    9月9
    JavaScript语法(三)
    JavaScript语法(二)
    实现AJAX的基本步骤 。。转
    Ajax 完整教程。。转载
    Struts2中的Action类(解耦方式,耦合方式)
    web应用中使用JavaMail发送邮件 。。转载
    Struts2下的<result>中的type整理
    Struts2整理+课堂代码+注意事项
    一对多,多对一,注意事项总结
  • 原文地址:https://www.cnblogs.com/skyleafcoder/p/12319556.html
Copyright © 2020-2023  润新知