关于pushdown函数
pushdown 函数在在线段树平衡树等数据结构中极为常见,由于本蒟蒻在刚开始学的时候没有理解其的奥妙,于是准备将曾经的疑惑讲出来,也算是弥补了。
首先,pushdown 通常用于修改,最常见的就是加减,他们的优势在于我们需要它的时候,才提前修改它的值,否则不鸟他。
这是一份常见的区间加减代码:
void change(int p,int l,int r,int k){
if(tree[p].l>=l&&tree[p].r<=r){
tree[p].dat+=k*(tree[p].r-tree[p].l+1),tree[p].add+=k;
return;
}
pushdown(p);
int mid=tree[p].l+tree[p].r>>1;
if(l<=mid)change(p*2,l,r,k);
if(r>mid)change(p*2+1,l,r,k);
pushup(p);
}
其中
int query(int p,int l,int r){
if(tree[p].l>=l&&tree[p].r<=r)return tree[p].dat;
int res=0,mid=tree[p].l+tree[p].r>>1;
pushdown(p);
int mid=tree[p].l+tree[p].r>>1;
if(l<=mid)res+=query(p*2,l,r);
if(r>mid)res+=query(p*2+1,l,r);
return res;
}
可以发现,我们在查询前提前将搜到的地方 pushdown,这样我们查到的答案就是修改完的。
这样我们就不需要
这时又会心生疑惑,如果在修改时不进行 pushdown 操作会怎么样呢,按道理来讲它好像也可以做对啊?
但是有一个严重的问题,如图:
我们先给区间
区间加减乘的 pushdown#
void pushdown(int p){
if(tree[p].add!=0||tree[p].mul!=1){
tree[p*2].dat=(tree[p*2].dat*tree[p].mul)%h;
tree[p*2+1].dat= (tree[p*2+1].dat*tree[p].mul)%h;
tree[p*2].dat=(tree[p*2].dat+tree[p].add*(tree[p*2].r-tree[p*2].l+1))%h;
tree[p*2+1].dat=(tree[p*2+1].dat+tree[p].add*(tree[p*2+1].r-tree[p*2+1].l+1))%h;
tree[p*2].mul=(tree[p*2].mul*tree[p].mul)%h;
tree[p*2+1].mul=(tree[p*2+1].mul*tree[p].mul)%h;
tree[p*2].add=(tree[p*2].add*tree[p].mul)%h;
tree[p*2+1].add=(tree[p*2+1].add*tree[p].mul)%h;
tree[p*2].add=(tree[p*2].add+tree[p].add)%h;
tree[p*2+1].add=(tree[p*2+1].add+tree[p].add)%h;
tree[p].add=0;
tree[p].mul=1;
}
}
它的原则是现乘再加 看起来就很正确,我们发现在乘的时候或 pushdown 的时候我们给
pushdown 函数不仅应用于线段树,还可以应用于平衡树等,原理都是一样的,重在理解。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?