线段树与树状数组
线段树与树状数组都是十分经典的数据结构,其实能用树状数组解决的问题也都能用线段树解决,但线段树相比于树状数组常数较大。
单点修改区间查询
线段树做法,树状数组做法,其实单纯实现这个还是用树状数组较好(毕竟常数小还好写)
区间修改区间查询
权值线段树/树状数组
其实就是正常线段树/树状数组维护的定义域下标为正常下标,现在为权值。
扫描线
这是个很重要的东西,可以解决二维数点问题。就是将两个维度的偏序关系一个维排序,另一个维用树状数组维护。求矩形面积并要用线段树维护。(详见此题)
不断插入区间,一边插入一边问给定[l,r],插入过的与[l,r]相交的区间有多少
答案其实就是:r之前的所有区间开头数(包括R)
区间可以拆成左右两个端点维护。(例)
线段树专讲
线段树其实就是通过几个小区间的信息,合并出一个大区间的信息,所以线段树的运算要满足结合律。对不同题目,我们要考虑记录不同的信息,要合并它们。
- 动态开点线段树
就是定义域下标范围太大,不能把整棵树开满,那就用一个点,看一个点
code:
点击查看代码
inline void update(int &o,int l,int r,int x,int val){
if(!o)o=++ncnt;//开点
if(l==r){
sum[o]+=val;return;
}
int mid=(l+r)>>1;
if(x<=mid)update(lc[o],l,mid,x,val);
else update(rc[o],mid+1,r,x,val);
pushup(o);
}
int ask(int o,int l,int r,int L,int R){
if(!o)return 0;//没这个点,直接返回0
if(L<=l && R>=r)return sum[o];
int val=0;
int mid=(l+r)>>1;
if(L<=mid)val+=ask(lc[o],l,mid,L,R);
if(R>mid)val+=ask(rc[o],mid+1,r,L,R);//递归计算
return val;
}
- 线段树二分,线段树上二分,听起来挺高深,其实就是像二分一样每次判断查询区间往右挪还是往左挪,然后想应该去的方向递归。
- 线段树维护区间最大子段和
线段树每个点维护四个信息,区间最大子段和,最大前缀,最大后缀,区间和。用这几个条件合并(例) - 结合树
对一棵子树修改/查询,由于字数内dfs序是连续的,用线段树维护。(例) - 区间修时取模操作
由于每次取模至少减半,所以一个数最多被修改 次,区间修时可以递到每个l==r更改,复杂度 (例) - 当我们每次对区间增加一个等差数列,求单点,可以线段树维护差分数组。(例)
- 当区间修改是要排序,并且值域范围不大时,可以在线段树每个点统计每个值在这个区间出现多少次,每次要对某区间排序时要先取出每个值出现多少次,然后按AAA..BB...CC..的方法进行值域大小次区间改(比如将第一个阶段区间的A数量改变)
树状数组专讲
单点修矩阵查
二维其实与一维没什么区别,就是两个维跳lowbit而已和二位前缀和。
矩阵修改矩阵查询
这个还是用树状数组解比较舒服,其实就是树状数组的单点修矩阵查加上区间修区间查的差分思想,要推的式子见这里
逆序对
向前走时加一个权值树状数组,其实相当于二维数点的一维已经排好序了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)