首页 > 其他 > 详细

线段树基础处理操作(详细注释)

时间:2020-04-26 22:09:40      阅读:73      评论:0      收藏:0      [点我收藏+]

二话不说,直接上代码!(懒)

#include<stdio.h>
#include<algorithm>
using namespace std;
#define Maxx 1000000
struct Tree{
    int l,r,sum;
}t[4*Maxx];//开四倍空间,防爆
int a[Maxx],add[Maxx],sum[Maxx];//sum每个节点的子节点数值的总和,add该节点的每个数值应该加多少 
int len;
void built_tree(int i,int l,int r){//简单建树
    t[i].l=l;
    t[i].r=r;
    if(l==r){
        t[i].sum=a[l];
        return;
    }
    int mid=(l+r)/2;
    built_tree(i*2+1,l,mid);//left
    built_tree(i*2+2,mid+1,r);//right
    t[i].sum=t[i*2+1].sum+t[i*2+2].sum;
}
void pushdown(int i,int m){//向下更新
    //从根节点i向下更新每个子节点的值,m为子节点个数
    if(add[i]){//判断是否有标记
        add[i*2+1]+=add[i];//+=特别注意,debug警告!
        add[i*2+2]+=add[i];
        t[i*2+1].sum+=add[i]*(m-(m>>1));//毕竟奇数时左边的比右边多个数
        t[i*2+2].sum+=add[i]*(m>>1);
        add[i]=0;//还原
    }
}
void chang_point(int i,int l,int r,int num,int x){//单点修改
    if(l==r){//num位置上的数加上x
        t[i].sum+=x;
        return;
    }
    pushdown(i,t[i].r-t[i].l+1);//向下更新
    int mid=(l+r)/2;
    if(num<=mid)    chang_point(i*2+1,l,mid,num,x);//在左边
    else            chang_point(i*2+2,mid+1,r,num,x);//在右边
}
int search_sum(int i,int l,int r){//区间查询
    int s=0;
    if(t[i].l>r || t[i].r<l){//不在范围
        return 0;
    }
    if(t[i].l>=l && t[i].r<=r){//(l,r)完全包含该节点,因此为s的一部分。
        return t[i].sum;
    }
    pushdown(i,t[i].r-t[i].l+1);//遇到标记向下更新
    int mid=(t[i].l+t[i].r)/2;
    if(r<=mid){
        s+=search_sum(i*2+1,l,r);//完全在节点左边
    }else if(l>mid){//debug>好久(mid在左区间)
        s+=search_sum(i*2+2,l,r);//完全在节点右边
    }else{//部分在左部分在右
        s+=search_sum(i*2+1,l,mid);
        s+=search_sum(i*2+2,mid+1,r);
    }
    return s;
}
void update(int i,int l,int r,int num){//区间修改
    //[l,r]每个数加num
    if(t[i].l==l && t[i].r==r){//提前结束
        add[i]+=num;//多次操作存在提前结束在同一个节点上,需要累加,+=!
        t[i].sum+=num*(r-l+1);//[l,r]每个数加num == 节点个数*num 
        return;
    }
    if(t[i].l==t[i].r)  return;//最低了,不能再下了!
    pushdown(i,t[i].r-t[i].l+1);//向下更新
    int mid=(t[i].l+t[i].r)/2;
    if(r<=mid){//完全在左
        update(i*2+1,l,r,num);
    }else if(l>mid){//完全在右
        update(i*2+2,l,r,num);
    }else{//左右都有一部分
        update(i*2+1,l,mid,num);//搜索左边
        update(i*2+2,mid+1,r,num);//搜索右边
    }
    t[i].sum=t[i*2+1].sum+t[i*2+2].sum;
}
int main()
{
    scanf("%d",&len);
    for(int i=0;i<len;i++){
        scanf("%d",&a[i]);//1 5 6 8 9 12 35 4 7
    }
    built_tree(0,0,len-1);//建树
    int sumlr=search_sum(0,1,3);//查询区间和
    printf("%d ",sumlr);
    update(0,1,3,5);//区间加数
    int sumlr2=search_sum(0,1,3);
    printf("%d ",sumlr2);
}

请忽略命名和码风那些,毕竟纯手打,临时编的变量名,怎么简单怎么来╰(*°▽°*)╯

线段树基础处理操作(详细注释)

原文:https://www.cnblogs.com/sizhen/p/12782071.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!