首页 > 其他分享 >线段树入门

线段树入门

时间:2022-11-02 15:22:16浏览次数:47  
标签:入门 递归 线段 tree mid 更新 区间 节点

是一种二叉搜索树,通过二分法访问或修改区间值,区间大小不超过10^6,区间值必须满足区间加法,即仅当对于区间 [ L , R ] 的问题的答案可以由 [ L , M ] 和 [ M + 1 , R ]的答案合并得到。
时间复杂度为log级

需要的数据:

arr[maxn],记录区间中的单点值
tree[maxn<<2]线段树数组
lazy[maxn<<2]延迟更新数组

操作流程

0.初始化

定义void型pushup函数,传入参数k,用k的儿子节点k<<1,k<<1|1,区间加法更新k节点

定义void型pushdown函数,传入参数k,更新k节点的儿子节点k<<1,k<<1|1,更新后lazy[k<<1]+=lazy[k],lazy[k<<1|1]+=lazy[k],lazy[k]=0表示k更新完毕,并将更新值传入儿子的延迟更新值

定义void型build递归函数构建线段树,传入参数(l=1,r=n,k=1),(l,r)表示当前递归层访问到的区间,初始值始终为(1,n),k表示当前区间(l,r)对应在线段树tree中的下标,初始值始终为1

build函数利用二分法搜索区间{(1,1),(2,2),(3,3)……}(l==r即为单点)对应在线段树tree的下标k,并赋值tree[k]为arr[l],表示区间(l,l)的值等于单点arr[l]的值
回溯时需要调用pushup函数,用儿子节点更新当前递归层的k节点

1.区间更新

定义void型change递归函数进行区间更新,传入参数(l=1,r=n,k=1,cl,cr,x),(l,r)表示当前递归层访问到的区间,初始值始终为(1,n),k表示当前区间(l,r)对应在线段树tree中的下标,初始值始终为1,(cl,cr)表示更新的区间,x表示更新的值
当(l,r)被包含在(cl,cr)中时,lazy[k]+=x表示将用x延迟更新区间(l,r)的父亲节点的值,并用x对当前区间(l,r)更新
调用pushdown函数,用当前递归层的k节点更新自己的儿子节点
设mid为(l+r)>>1,如果cl<=mid,递归至(l,mid,k<<1,cl,cr,x),查询(l,mid)区间,如果cr>mid,递归至(mid+1,r,k<<1|1,cl,cr,x),查询(mid+1,r)区间
回溯时需要调用pushup函数,用儿子节点更新当前递归层的k节点

2.区间查询

定义int 型query递归函数,传入参数(l=1,r=n,k=1,ql,qr),(l,r)表示当前递归层访问到的区间,初始值始终为(1,n),k表示当前区间(l,r)对应在线段树tree中的下标,初始值始终为1,(ql,qr)表示查询的区间
当(l,r)被包含在(cl,cr)中时,返回tree[k],即该区间的值
调用pushdown函数,用当前递归层的k节点更新自己的儿子节点
设a为当前区间(l,r)的区间值
设mid为(l+r)>>1,如果cl<=mid,递归至(l,mid,k<<1,cl,cr,x),(l,mid)区间,如果cr>mid,递归至(mid+1,r,k<<1|1,cl,cr,x),查询(mid+1,r)区间
更新a值为 区间加法((l,mid)值,(mid+1,r)值),返回a

难点

步骤繁杂,容易出错,debug困难

优化

1.动态开点,可节约空间,tree和lazy的大小减小到maxn<<1,用lson[maxn<<1],rson[maxn<<1]记录每个节点的左右孩子的下标,在build和change时需要在函数体最开头加if(!k)k=++cnt,在query时需要在函数体最开头加if(!k)return 0.
2.离散化,可压缩区间,极大节约空间,但会浪费时间,目前尚未实现

 

伪代码:

 

int tree[maxn<<2],lazy[maxn<<2];
void pushdown(int m,int k)
{
    if(lazy[k])
    {
        lazy[k<<1]+=lazy[k];
        lazy[k<<1|1]+=lazy[k];
        tree[k<<1]+= (m - (m>>1))*lazy[k];
        tree[k<<1|1]+=(m>>1)*lazy[k];
        lazy[k]=0;
    }
}
void build(int l,int r,int k)
{
    if(l==r)
    {
        scanf("%lld",&tree[k]);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    tree[k]=tree[k<<1]+tree[k<<1|1];
}
int  query(int l,int r,int k,int ql,int qr)
{
    if(ql <= l&&r <= qr)return tree[k];
    int  sum=0;
    int mid=(l+r)>>1;
    pushdown(r-l+1,k);
    if(ql<=mid)sum+= query(l,mid,k<<1,ql,qr);
    if(qr>mid)sum+= query(mid+1,r,k<<1|1,ql,qr);
    return sum;
}
void change(int l,int r,int k,int cl,int cr,int x)
{
    if(cl <= l&&r <= cr)
    {
        tree[k]+=(ll)(r-l+1)*x;
        lazy[k]+=x;
        return;
    }
    pushdown(r-l+1,k);
    int mid=(l+r)>>1;
    if(cl<=mid)change(l,mid,k<<1,cl,cr,x);
    if(cr>mid)change(mid+1,r,k<<1|1,cl,cr,x);
    tree[k]=tree[k<<1]+tree[k<<1|1];
}

 

标签:入门,递归,线段,tree,mid,更新,区间,节点
From: https://www.cnblogs.com/alineyyds/p/16851103.html

相关文章

  • day12 --> (Web概念回顾、Tomcat服务器、Servlet入门)
    Web相关概念的回顾: 1.软件架构:1.B/S:浏览器/服务器端2.C/S:客户端/服务器端2.资源分类:1.静态资源:所有用户访问后,得到的结果都是一样的,称之为静态资源如:html、......
  • AutoCAD 数据库入门
    1.AutoCAD数据库概述AutoCAD图形是存储在数据库中的对象集合。一些基本的数据库对象是实体、符号表和字典。实体是一种特殊的数据库对象,在AutoCAD图形中具有图形表示......
  • Excel VBA 新手入门学习,只要你记住这些基础知识就可以
    相信很多人在犹豫自己要不要学习Excel函数或者VBA,有的人只在学习基础版的粘贴复制,有的人学会用函数,甚至还有的人,学会用PQ或者VBA来提升自己的工作效率,在大多数时候,我们学习......
  • 快速入门修改密码
    技术:bootstarp+jquery+ajax+thymeleaf(了解程度)功能描述:单击修改密码=>弹出模态框=>模态框内容有原密码、新密码、确认密码是三行+确认与取消按钮效果展示:文字有......
  • Unity坐标系入门
    一、坐标系的概念Unity世界坐标系采用左手坐标系,大拇指指向X轴(红色),食指指向Y轴(黄色),中指向手心方向歪曲90度表示Z轴(蓝色),同时Z轴也是物体前进方向,下图表示Unity的四......
  • Flutter官方推荐的状态管理库-Provider简单入门
    最近几年崛起的新一代的GUI开发方式,几乎都是组件式开发。代表就是VueReactFlutter等。组件开发一时爽,状态传递就很蛋疼了。比如A和B组件没有上下级关系,也不是层级相近......
  • Azure DevOps Server 入门实践与安装部署
    一,引言最近一段时间,公司希望在自己的服务器上安装本地版的AzureDevOpsService(AzureDevOpsServer),用于项目内的测试,学习。本着学习的目的,我也就开始学习在测试服务......
  • C# Linq学习笔记(一)-基础语法入门
    一、简介:Linq(语言集成查询):为C#和VisualBasic提供语言级查询功能和高阶函数API,让你能够编写具有很高表达力度的声明性代码。二、优点:1、LINQ具有语言级查询语法,切......
  • Mac新手必看Mac入门基本知识图文教程
    你已经是Mac的用户了吗?还是准备入手的新手呢?赶快看看“Mac入门基本知识”吧!macbook系统基础内容简介Mac入门基本知识1、主界面结构图基本知识介绍(如图所示)2、Ma......
  • L - Intersection and Union Gym - 103993L (线段树)
    题意思路思路很巧妙,首先是枚举每个值的贡献,然后找到了规律,下次做题的时候线分析每个题有啥好规律,然后根据规律做题。再就是线段树的这个思路,感觉很巧妙,通过设置每一段的......