线段树原理 and 例题

线段树详解 (原理,实现与应用) 线段树详解 By 岩之痕 一:综述 线段树是一种可以快速进行区间修改和区间查询的数据结构。点修改,区间修改和区间查询的复杂度都是O(log2(n)) 并且,线段树可以维护很多种类的信息。说到线段树就不得不提一下树状数组,树状数组维护的信息必须满足区间减法,因为树状数组只是维护1到X的信息,通过相减来得到区间信息,代码简单而且速度快,占用空间又少于线段树,所以一般情况下可以用树状数组的地方就 阅读详情

线段树的原理是根据满二叉树得出的一棵满二叉树一定可以储存在一个一位的数组中其中

如果当前节点为u那么其子节点为u<<1和u<<1|1

一颗不包括pushdown的操作的线段树可以实现单点修改区间查询而包括了懒标记和pushup就可以区间修改区间查询了

主要的原理就是我们把一个完全的区间看成一个根把区间分为左右两个 [l,mid] [mid+1,r]那么这就是它的左右子树 直到分的只有一个元素的时候就停止 一般情况下节点的个数就是N*4

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'

const int N=2e5+10;

typedef long long ll;

int m,p;

struct node{

       int l,r,v;//根据求的性质不同 结构体存储的数据也不同 pushup也可能不同

}tr[N*4];

void pushup(int u){

       tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);

}

void build(int u,int l,int r){

       tr[u]={l,r};

       if(l==r)return ;//如果只有一个元素就停止

       int mid=l+r>>1;

       build(u<<1,l,mid);//左

       build(u<<1|1,mid+1,r);//右

}

int query(int u,int l,int r){

       if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;//如果查询区间完全包括当前节点区间那么直接返回信息

       int mid=tr[u].l+tr[u].r>>1;

       int v=0;

       if(l<=mid)v=query(u<<1,l,r);//如果和左边的有交集就查询左边

       if(r>mid)v=max(v,query(u<<1|1,l,r));如果和右边的有交集就查询右边

       return v;//返回信息

}

void modify(int u,int x,int v){

       if(tr[u].l==x&&tr[u].r==x)tr[u].v=v;

       else{

              int mid=tr[u].l+tr[u].r>>1;

              if(x<=mid)modify(u<<1,x,v);

              else modify(u<<1|1,x,v);

              pushup(u);

       }

}

int main(){

       ios::sync_with_stdio(false);

       cin.tie(0);

       cout.tie(0);

       int n=0,last=0;

       int x;

       char op[2];

       cin>>m>>p;

       build(1,1,m);

       while(m--){

              cin>>op>>x;

              if(*op=='Q'){

                     last=query(1,n-x+1,n);

                     cout<<last<<endl;

              }

              else{

                     modify(1,n+1,((LL)last+x)%p);

                     n++;

              }

       }

}

例题1你能回答这些问题吗

        

e944cf429e6040a29a5754e584add531.png

不需要懒标记的线段树 但是一个节点储存的信息不再是最大值这么简单

首先 我要对query操作进行一些理解和补充 在build操作里我们pushup是直接根据

已经划分好的区间 通过子节点对父节点信息 进行更新 但是在query的时候我们的所查询的区间可能不会刚刚好就来自通一个父节点的直接子节点就是说

88f8545548364f6fbfac53999ccc7e39.jpeg

像这样我们查询的区间来自两个红色的节点 那么

我们的u就不能更新通过 tr[u] tr[u<<1] tr[u<<1|1]而是通过这两个区间来更新

那么我们就分别需要三个node

一个表示 答案 res 一个表示右区间right 一个表示左区间left

push(res,right,left);

retrun res;

具体代码

node query(int u,int l,int r)

{

 If(tr[u].l>=l&&tr[u].r<=r)return tr[u];//当我们的当前节点的区间完全被查询的时候直接返回

int mid=tr[u].l+tr[u].r>>1;

if(r<=mid)return query(u<<1,l,r);//当我们查询的区间完全在左边就直接返回左边查询结果

else if(l>mid) return query(u<<1|1,l,r);//当我们查询的区间完全在右边就直接返回右边查询结果

else{//两边皆包括一部分

node res;

node left=query(u<<1,l,r);

node right=query(u<<1|1,l,r);

pushup(res,left,right);

return res;

}

而在有些简单的只储存一个信息的节点的时候 我们也可以不pushup而是直接计算 然后讲答案返回

那么这个题目我们最大连续区间

可能完全来自左边 可能完全来自右边 可能有一部分来自左边 有一部分来自右边

而一部分来自左边一部分来自右边的一定是左边的最大后缀和与右边的最大前缀和的和

而最大后缀和可能是其右区间的最大后缀和也可能是其右区间的总和和其左区间的最大后缀和最大前缀和同理

所以一个节点需要储存的信息 有:最大连续子段和,最大前缀和,最大后缀和,总和

Code:

#include<bits/stdc++.h>

#define endl '\n'

using namespace std;

const int N=500010;

typedef long long ll;

typedef pair<int,int>PII;

int w[N];

struct node{

       int l,r;

       int sum;

       int tsum;

       int lsum,rsum;

}tr[N*4];

void pushup(node&l,node&r,node&u){

       u.sum=l.sum+r.sum;

       u.lsum=max(l.lsum,l.sum+r.lsum);

       u.rsum=max(r.rsum,r.sum+l.rsum);

       u.tsum=max(max(l.tsum,r.tsum),l.rsum+r.lsum);

}

void pushup(int u){

       pushup(tr[u<<1],tr[u<<1|1],tr[u]);

}

void build(int u,int l,int r){

       if(l==r){

              tr[u]={l,r,w[l],w[l],w[l],w[l]};

              return ;  

       }

       tr[u]={l,r};

       int mid=l+r>>1;

       build(u<<1,l,mid);

       build(u<<1|1,mid+1,r);

       pushup(u);

}

node query(int u,int l,int r){

       if(l<=tr[u].l&&tr[u].r<=r)return tr[u];

       int mid=tr[u].l+tr[u].r>>1;

       if(r<=mid)return query(u<<1,l,r);

       if(l>mid)return query(u<<1|1,l,r);

       node left=query(u<<1,l,r);

       node right=query(u<<1|1,l,r);

       node res;

       pushup(left,right,res);

       return res;

}

void modify(int u,int x,int v){

       if(tr[u].l==x&&tr[u].r==x){

              tr[u].lsum=tr[u].rsum=tr[u].sum=tr[u].tsum=v;

              return ;

       }

       int mid=(tr[u].l+tr[u].r)>>1;

       if(x<=mid)modify(u<<1,x,v);

       else modify(u<<1|1,x,v);

       pushup(u);

}

int main(){

       ios::sync_with_stdio(false);

       cin.tie(0);

       cout.tie(0);

       int n,m;

       cin>>n>>m;

       for(int i=1;i<=n;i++)cin>>w[i];

       build(1,1,n);

       while(m--){

              int k,x,y;

              cin>>k>>x>>y;

              if(k==1){

                     if(x>y)swap(x,y);

                     node res=query(1,x,y);

                     cout<<res.tsum<<endl;

              }

              else{

                     w[x]=y;

                     modify(1,x,y);

              }

       }

}

例题2区间最大公约数

751865d794774c90bb07b0d6fa050d68.png

没有懒标记的线段树 适用于单点修改区间查询

但是这个题目对区间修改了 乍一看没法用线段树 但是只是对区间加减没有直接使得一个区间变成一个元素这种操作 那么我们可以用差分处理 仍是单点修改

值得一提的是gcd存在这样一个性质

求gcd(a1,a2)=gcd(a1,a2-a1)

gcd(a1,a2,a3,a4...)=gcd(a1,a2-a1,a3-a2,a4-a3...)

那么 差分数组 bi=ai-ai-1那么这不就是一个差分数组吗

只不过第一个点不是而已

而第一个点可以通过计算差分数组的前缀和得出

也可以用线段树来实现

所以线段树里存的信息就是 gcd(al-al-1,al+1-al...,ar-1-ar-2,ar-ar-1)和sum[r]-sum[l-1]

查询的时候需要查询两次一次是找sum[l]一次是找gcd(bl+1,bl+2,..br-1,br+2)

bl=al-al-1;

修改的时候也是两次

bl+d br+1-d(差分技巧)

code:

#include<bits/stdc++.h>

#define endl '\n'

using namespace std;

const int N=500010;

typedef long long ll;

typedef pair<int,int>PII;

ll b[N];

int n,m;

struct node{

       int l,r;

       ll d,sum;

}tr[4*N];

ll gcd(ll a,ll b){

       return b==0?a:gcd(b,a%b);

}

void pushup(node&u,node&l,node&r){

       u.d=gcd(l.d,r.d);

       u.sum=l.sum+r.sum;

}

void pushup(int u){

       pushup(tr[u],tr[u<<1],tr[u<<1|1]);

}

void build(int u,int l,int r){

       if(l==r){

              tr[u]={l,r,b[l],b[l]};

              return ;

       }

       tr[u].l=l,tr[u].r=r;

       int mid=l+r>>1;

       build(u<<1,l,mid);

       build(u<<1|1,mid+1,r);

       pushup(u);

}

node query(int u,int l,int r){

       if(tr[u].l>=l&&tr[u].r<=r)return tr[u];

       int mid=tr[u].l+tr[u].r>>1;

       ll d=0;

       if(r<=mid)return query(u<<1,l,r);

       else if(l>mid)return query(u<<1|1,l,r);

       else{

              node res;

              node left=query(u<<1,l,r);

              node right=query(u<<1|1,l,r);

              pushup(res,left,right);

              return res;

       }

}

void modify(int u,int x,ll v){

       if(tr[u].l==x&&tr[u].r==x){

              tr[u].d+=v;

              tr[u].sum+=v;

              return ;

       }

       int mid=tr[u].l+tr[u].r>>1;

       if(x<=mid)modify(u<<1,x,v);

       else modify(u<<1|1,x,v);

       pushup(u);

}

int main(){

       ios::sync_with_stdio(false);

       cin.tie(0);

       cout.tie(0);

       cin>>n>>m;

       ll now,last=0;

       for(int i=1;i<=n;i++){

              cin>>now;

              b[i]=now-last;

              last=now;

       }

       build(1,1,n);

       char op[2];

       int l,r;

       ll d;

       while(m--){

              cin>>op>>l>>r;

              if(op[0]=='Q'){

                     node res=query(1,1,l);

                     node tt={0,0,0,0};

                     if(l+1<=r)tt=query(1,l+1,r);

                     ll ans=abs(gcd(res.sum,tt.d));

                     cout<<ans<<endl;

              }

              else{

                     cin>>d;

                     modify(1,l,d);

                     if(r!=n)modify(1,r+1,-d);

              }

       }

}

例题3 一个简单的小问题2

 

1773e8219c554024bd78c7b765291385.png

这个就不得不用懒标记了

懒标记的意思是如果我们要修改的区间完全包括了当前节点的区间 那么在这个节点标记即可 然而多次修改的时候 如果当前节点区间并不是完全被包括了 那么我们就需要讲当前节点的懒标记给到其两个子节点而自己的懒标记清0为什么需要这样做呢?看下图

e8c32f1e1a3b45b0bde971e86048578c.jpeg

如在当前节点已经标记了+10 那么我们想在红色区域+5当前节点肯定无法表示 那么就需要往下分 那么被红色框起来的区域+15而其他区域+10同一个标记无法表示所以需要pushdown也就是把标记给到下面

而查询的时候也是如此

如果当前节点的区间并不完全被查询区间包括我们就需要讲当前节点的标记给到左右两个区间

因为懒标记是标记到当前节点就结束了那么下面的节点并没有被更新 我们需要用到下面节点的信息 所以需要pushdown

Code:

#include<bits/stdc++.h>

#define endl '\n'

using namespace std;

const int N=1e5+10;

typedef long long ll;

typedef pair<int,int>PII;

struct node{

       int l,r;

       ll sum,add;

}tr[N*4];

int a[N];

void pushup(node&u,node&l,node&r){

       u.sum=l.sum+r.sum;

}

void pushup(int u){

       pushup(tr[u],tr[u<<1],tr[u<<1|1]);

}

void pushdown(int u){

       if(tr[u].add){

              tr[u<<1].sum+=(ll)(tr[u<<1].r-tr[u<<1].l+1)*tr[u].add;

              tr[u<<1].add+=tr[u].add;

              tr[u<<1|1].sum+=(ll)(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].add;

              tr[u<<1|1].add+=tr[u].add;

              tr[u].add=0;

       }

}

void build(int u,int l,int r){

       if(l==r){

              tr[u]={l,r,a[l],0};

              return ;

       }

       tr[u]={l,r};

       int mid=l+r>>1;

       build(u<<1,l,mid);

       build(u<<1|1,mid+1,r);

       pushup(u);

}

node query(int u,int l, int r){

       if(tr[u].l>=l&&tr[u].r<=r)return tr[u];

       pushdown(u);

       int mid=tr[u].l+tr[u].r>>1;

       if(r<=mid)return query(u<<1,l,r);

       else if(l>mid)return query(u<<1|1,l,r);

       else{

              node res;

              node left=query(u<<1,l,r);

              node right=query(u<<1|1,l,r);

              pushup(res,left,right);

              return res;

       }

}

void modify(int u,int l,int r,int d){

       if(tr[u].l>=l&&tr[u].r<=r){

              tr[u].add+=d;

              tr[u].sum+=(ll)(tr[u].r-tr[u].l+1)*d;

              return ;

       }

       pushdown(u);

       int mid=tr[u].l+tr[u].r>>1;

       if(l<=mid)modify(u<<1,l,r,d);

       if(r>mid)modify(u<<1|1,l,r,d);

       pushup(u);

}

int main(){

       ios::sync_with_stdio(false);

       cin.tie(0);

       cout.tie(0);

       int n,m;

       cin>>n>>m;

       for(int i=1;i<=n;i++)cin>>a[i];

       build(1,1,n);

       while(m--){

              char op[2];

              int l,r,d;

              cin>>op>>l>>r;

              if(op[0]=='C'){

                     cin>>d;

                     modify(1,l,r,d);

              }

              else{

                     node res=query(1,l,r);

                     cout<<res.sum<<endl;

              }

       }

}

 

 

 

线段树详解 (原理,实现与应用) 线段树详解 (原理,实现与应用) 线段树是一棵完美二叉树,树上的每个节点都维护一个区间。根维护的是整个区间,每个节点维护的是父亲的区间二等分后的其中一个子区间。 立即下载

相关推荐

支付系统保证可靠性的秘诀 ----- 订单的补偿和补单

文章目录WHAT? 前言WHY? 为什么要用多级缓存?HOW 怎么做?方案 版本1:数据库存储专线配置通过优先级进行动态上下线方案 版本1 劣势:方案 版本2 :本地缓存替代数据库方案 版本2 劣势:方案 版本3:分布式缓存做自动补偿方案 版本3 总结:Where 分布式多级缓存还能用在哪些地方?总结 WHAT? 前言 刚入职场的时候觉得支付宝等第三方支付系统好强大,要保证这么多的交易不能错,也不能重复还要保证正确的扣钱,直到后面接触订单系统以及第三方支付公司的核心交易系统后才真正窥探到了支付系统的核心

boboaisisi的专栏 3534

1785 数据流中的算法(统计问题——区间中位数的维护:STL multiset / 线段树)

1785 数据流中的算法 51nod近日上线了用户满意度检测工具,使用高级人工智能算法,通过用户访问时间、鼠标轨迹 等特征计算用户对于网站的满意程度。 现有的统计工具只能统计某一个窗口中,用户的满意程度的均值。夹克老爷想让你为统计工具添 加一个新feature,即在统计均值的同时,计算窗口中满意程度的标准差和中位数(均值需要向下取整)。 输入 第一行是整数n与k,代表有n次操...

又菜又爱玩 1069

复现基于PYNQ-Z2的手写数字识别卷积加速器设计

来源雪天鱼。

eachanm的博客 968

线段树

线段树 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。 基本信息 中文名称 线段树 外文名称 Segment Tre...

weixin_44006014的博客 273

【数字电源/MATLAB+PLECS】如何进行 Buck 数字电源仿真(二)PLECS 搭建开环 Buck 功率级

本文介绍了如何在PLECS中搭建开环Buck功率级模型,验证数字电源设计的基本思路。重点内容包括: 明确开发顺序:先开环验证功率级,再闭环设计控制器 搭建关键组件:输入电源、PWM模块、MOSFET开关、续流二极管、LC滤波电路及负载 设置初始参数:24V输入、12V输出、200kHz开关频率、22μH电感、100μF电容 测量关键波形:MOSFET Vds验证开关动作、电感电流纹波和输出电压稳态值 提供完整仿真模型和GitHub资源,便于读者复现验证 文章强调通过开环测试先确保功率级正确性,为后续闭环控制

weixin_43234123的博客 1218

LVGL 实战:虚拟列表与对象复用机制在嵌入式GUI中的性能优化

本文深入探讨LVGL虚拟列表与对象复用机制在嵌入式GUI中的性能优化实践。通过复用机制动态管理UI对象,大幅降低内存占用,实现无限滚动列表的流畅体验。文章详细解析核心算法、内存优化策略及跨平台适配技巧,帮助开发者在资源受限设备上高效处理大量数据展示。

rice5的博客 1106

2018.8.8T1(线段树、stl)

描述 作为一场快乐的模拟赛,需要一道歌颂友谊的题目。 你从来不知道,友谊的巨轮是单向的,直到有一天他和她在了一起。 这个地球上一共有n个人,他们之间会互相发消息。在每个时刻,a与b之间互相发了c条消息。对于每个人,他友谊的巨轮为最近m个时刻里与他发消息最多的人,如果有多个发消息最多的人,那么巨轮为这里面最近发的人。如果这个人在最近mm个时刻里面没有与任何人发过消息,那么它没有友谊的巨轮。 ...

a1035719430的博客 779

Windows 11“此应用已被管理员阻止运行”解决方案

通过本文介绍的两种方法,你应该能够解决Windows 11中“此应用已被管理员阻止运行”的问题。无论你选择创建新管理员账户还是禁用管理员批准模式,都请确保了解相关操作的风险,并根据你的实际需求做出选择。通过禁用“用户账户控制:以管理员批准模式运行所有管理员”设置,可以解决因系统安全设置导致的应用程序被阻止运行的问题。这种方法适用于那些希望简化管理员账户操作流程的用户,但需要注意可能带来的安全风险。通过创建并登录具有管理员权限的新账户,可以解决因系统安全设置导致的应用程序被阻止运行的问题。

mmoo_python的博客 1万+

2020牛客多校二H Happy Triangle (STL 线段树)

题意:一个集合可以对其做三种操作,加上一个x,减去一个已有x,给出一个x问时候存在a和b使得abx可以围成一个三角形 分析:看到集合操作马上想到用set,其中可以再用set的指针在map上记录下所以数值之间的差,但这时存在一个问题就是可能存在两个数,这两个数的差满足条件但两个数的和却太小不到x,因此我所用的方法就是提前把所有差都求出来后离散键线段树,线段树上存的是该差中的最大和,这样再动态对每个操作进行修改查询 代码: #include <bits/stdc++.h> #define x

圣诞老头的博客 358

Unity2020 发布Android包,下载安装配置JDK、SDK、NDK详细教程

配置成功页面 JDK、SDK、NDK

qq_41263535的博客 1万+

英飞凌TC3xx实战:PWM中点触发ADC采集+DMA自动搬运完整配置流程(基于ILLD库)

本文详细介绍了在英飞凌TC3xx系列微控制器上使用ILLD库实现PWM中点触发ADC采集并通过DMA自动搬运数据的完整配置流程。该方案适用于电机控制、电源管理等需要高精度定时采集的场景,通过GTM生成PWM信号、ADC采集和DMA传输实现全硬件自动化流程,显著提升系统效率。

weixin_42536058的博客 534

线段树的原理与模板

如果会树状数组的同学应该就很容易理解线段树了,在一定程度上,两者是有一点类似的。首先,了解一下我们为什么要使用线段树,以及线段树的主要作用。 区间求和问题-医院卖药 假设有一家医院,医院有卖药的地方,不同的药品有不同的数量。每次开药、进药都要在计算机里面记录数量变化,这样方便医院的管理。那么我们该如何实现这样的程序?当然,药品数量的储存用数组是比较合适的(真实的...

iwts 1万+

《派出你的AI同事:WorkBuddy案例实战》062:投研资讯摘要与预警

投研资讯摘要与预警:新闻、公告、行情交给 AI 同事提炼与预警,投研从“刷资讯”变成“读摘要”。

LuckyHanMo的博客 182

线段树模型及例题整理

还是先来看如何定义结构体,显然我们需要储存最大连续子段和,但是这样够不够呢,显然是不够的,因为子节点无法更新父节点,虽然父区间的最大值有可能是左右子区间中的一段,但是还有可能是跨区间的,如果是跨区间的话,要想更新就需要用到左区间的最大后缀和右区间的最大前缀,那么现在就要多维护两个变量——最长前缀和最长后缀,那么现在考虑最长前缀和最长后缀能否能通过子节点来更新父节点,显然是不可以,以最长前缀为例,要用子节点计算的话,有两种情况,一种就是左子节点的最长前缀,一种是左区间加右区间的最大前缀。

m0_74120503的博客 859

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

线段树入门 + 例题

目录 一、线段树简介 1、导入线段树 2、线段树的常识 二、线段树的操作 1、建树 2、区间查询 3、区间修改 一、线段树简介 1、导入线段树 如题,已知一个数列,每次操作读入 X : X==1 将[L,R]区间每一个数加上k。 X==2 求出某区间每一个数的和。 这是洛谷的P3372,在你没学线段树之前,有两种很简单地方法: 方法一 方法二 名称 暴力 前缀和 区间加 k 1 R...

m0_61405003的博客 601

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

线段树详解(附图解,模板及经典例题分析)

线段树是一种常用来维护区间信息的数据结构 ​ 可以在 O(logn) 的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间的最大值,求区间的最小值)等操作 ​ 如下图所示,线段树是建立在区间基础上的树,树的每个节点都代表着一段区间【L,R】

qq_63786973的博客 3896

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

线段树基础(下)

线段树基础。

wanglianda2007的博客 2220

蓝桥杯第十三讲--树状数组与线段树【例题】

蓝桥杯官网:蓝桥杯大赛——全国大学生TMT行业赛事;本博客讲解 蓝桥杯C/C++ 备赛所涉及算法知识,此博客为第十三讲:树状数组与线段树【例题】本篇博客所包含习题有:动态求连续区间和,数星星,数列区间最大值;树状数组与线段树【习题】见博客:蓝桥杯第十三讲–树状数组与线段树【习题】博客内容以题代讲,通过讲解题目的做法来帮助读者快速理解算法内容,需要注意:学习算法不能光过脑,更要实践,请读者务必自己敲写一遍本博客相关代码!!!

佛系更新 2209

线段树总结及例题 - 【数据结构】

线段树 最近在学线段树,这个东西真的是有点难度,看了我整整两天才理解他的意思,其中最难的我觉得就是对懒惰标记的理解吧。 引言: 有一些题目,总是跟区间相关,比如求区间上的最大值与最小值,但是我们要的是n次询问,每次求最大值最小值,暴力就会t,不解释,可以用RMQ,也可以用线段树做。再比如说,每次询问一段区间的和,前缀和对吧?的确可以做。那我修改一下,每次询问有两种情况,即将某一区间的每个数加上一个...

tran_sient的博客 409

线段树的原理及代码实现(附例题分析)

前言 有时我们需要对数组中[i, j]区间中的所有值进行操作,这样的操作对于普通的树来说是十分麻烦的,所以我们引入了新的一种树——线段树。 线段树 线段树(segment tree),顾名思义, 是用来存放给定区间(segment, or interval)内对应信息的一种数据结构。即线段树的每一个节点代表一段区间,而节点的值代表区间的一个性质,他可以是区间的和、区间的最大公约数。。。 使...

qq_39747794的博客 801

线段树(原理、构造和区间查询,例题:Balanced Lineup)

线段树是分治法和二叉树的结合,二叉树上的节点都是根据分治得到的。节点所表示的,也就是线段,可以是区间和、最值或者是其他的,,每次分治,左右子树各一半,每个节点的值代表了以它为根的子树上所有节点的值。通过线段树,大区间的解可以从小区间的解合并而来。

2301_77214603的博客 1984

线段树合并(四道例题)

顾名思义,就是合并两个同构(就是维护的区间长度一样)线段树,其实也没啥比较nb的算法,就是一个一个节点的合并,但是如果在n个要合并的线段树里,如果一共有m个元素,则配合动态开点,复杂度会均摊成一个惊人的O(mlogn)O(mlogn)O(mlogn)所以,在多次合并的均摊复杂度是非常优秀的.另外线段树合并还可以和线段树分裂一起构成维护一组线段树森林的方法 我们每次合并一个点,就是综合两个线段树表示...

平凡人Kalzn的博客 2007

最全线段树例题

例题1: 给一个长度n的序列,对于每个询问 询问区间内最大连续和 一、一个区间的最大子段和有三种情况 1、左子区间的最大子段和 2、右子区间的最大子段和 3、横跨左右子区间 二、每个结点需要维护的信息 1、区间和sum 2、从区间左端点开始的最大子段和lgss 3、从区间右端点开始的最大子段和rgss 4、区间最大子段和gss 三、建树 1、遇到叶子节点就...

yihanyifan的博客 1103

权值线段树

权值线段树

zc2000911的博客 1416

详解线段树

但是在做题的时候还是会对模板进行修改,修改的点主要在区间val的意义上,我们这里模板里面val代表的是区间和,但后面题目里面可能是 区间最大值 、区间最小值…,但是万变不离其宗,线段树的结构是不会变的。

潜心钻研技术 1353
上一篇: 二分图/二分图最大匹配(匈牙利算法)
姐姐带你拿捏大厂算法
博客等级 码龄5年 17粉丝 19原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值