线段树学习

参考两位神犇的博客:
https://www.cnblogs.com/TenosDoIt/p/3453089.html
https://www.cnblogs.com/TheRoadToTheGold/p/6254255.html
好吧终于学了线段树,核心思想是二分,然后构建一个完全二叉树,根节点表示区间[l,r],左儿子表示区间[l,mid],右儿子表示区间[mid+1,r],叶节点l==r。
每个节点可以存区间和,区间最值。
预处理时间O(n),查询时间O(logn),更新时间O(logn),需要额外的空间O(n)。
讲道理还是蛮好理解的,懒标记做区间修改待更新。。。

//线段树模板
//此模板为维护区间和的线段树为例
struct node
{
    int l,r,w;//l,r分别表示区间左右端点,w表示区间和
}tree[4*n+1];//结构体要开4倍空间
//建树
//l:左端点;r:右端点;root:当前根节点的下标
void build(int l,int r,int root)
{
    tree[root].l=l;tree[root].r=r;
    if(l==r)
        tree[root].w=arr[l];
    else
    {
        int mid=(l+r)/2;
        build(l,mid,root*2);//递归构造左子树
        build(mid+1,r,root*2+1);//递归构造右子树
        tree[root].w=tree[k*2].w+tree[k*2+1].w;//根据左右子树根节点的值,更新当前根节点的值
    }
}
//单点查询
//单点查询的思路就是二分
//区间查询
//区间查询的思想是选出一些区间,使他们相连后恰好涵盖整个查询区间,因此线段树适合解决“相邻的区间的信息可以被合并成两个区间的并区间的信息”的问题。
//以查询[x,y]的区间和为例
int query(int k)
{
    if(tree[k].l>=x&&tree[k].r<=y) 
    {
        ans+=tree[k].w;//当前区间被完全包含在[x,y]中,直接加上
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(x<=m) sum(k*2);//当前区间的左半边与[x,y]有重合,则递归查询左子树
    if(y>m) sum(k*2+1);//当前区间的右半边与[x,y]有重合,则递归查询右子树
}
//单点修改
//单点修改的思路是找到二分x的位置,根据建树原理,修改每个节点
//以给第k个数加y为例
void add(int k)
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].w+=y;
        return ;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(x<=m) add(k*2);
    else add(k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//将所有包含k节点的区间更新
}
//区间修改
//
/**/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值