线段树
基础
建树
void build(int pos,int l,int r) { if(r<l) return; if(l==r){scanf("%lf",&tree[pos].sum);return;} int mid=l+r>>1; build(pos*2,l,mid);build(pos*2+1,mid+1,r); tree[pos].sum=tree[pos*2].sum+tree[pos*2+1].sum; }
区间修改
void update(LL pos,LL l,LL r,LL ll,LL rr,LL num){ if(ll<=l&&rr>=r){ tree[pos].sum=tree[pos].sum*mod+(LL)x*(r-l+1); laz1[pos]*=mod;tree[pos].laz2=tree[pos].laz2*mod+num; return; }LL mid=(l+r)>>1;pushdown(pos,mid-l+1,r-mid); if(mid>=ll) update(pos<<1,l,mid,ll,rr,num); if(mid<rr) update(pos<<1|1,mid+1,r,ll,rr,num); tree[pos].sum=tree[pos<<1].sum+tree[pos<<1|1].sum; }
懒标记(乘+加)

void pushdown(LL pos,LL len1,LL len2){ if(tree[pos].laz2){ laz1[pos<<1]*=laz1[pos]; laz1[pos<<1|1]*=laz1[pos]; tree[pos<<1].laz2=tree[pos<<1].laz2*laz1[pos]+tree[pos].laz2; tree[pos<<1|1].laz2=tree[pos<<1|1].laz2*laz1[pos]+tree[pos].laz2; tree[pos<<1].sum=tree[pos<<1].sum*laz1[pos]+tree[pos].laz2*len1; tree[pos<<1|1].sum=tree[pos<<1|1].sum*laz1[pos]+tree[pos].laz2*len2; laz1[pos]=1;tree[pos].laz2=0; } }
(更改)

void pushdown(LL pos,LL l1,LL l2){ if(tree[pos].laz){ tree[pos<<1].laz=tree[pos].laz; tree[pos<<1|1].laz=tree[pos].laz; tree[pos<<1].sum=l1*tree[pos].laz; tree[pos<<1|1].sum=tree[pos].laz*l2; tree[pos].laz=0; } }
查询(区间)

double query(long long pos,long long l,long long r,long long ll,long long rr) { if(l>rr||r<ll) return 0; if(ll<=l&&r<=rr) return tree[pos].sum; long long mid=(l+r)>>1; pushdown(pos,mid-l+1,r-mid); return query(pos*2,l,mid,ll,rr)+query(pos*2+1,mid+1,r,ll,rr); }
(单点)
int query(int pos,int l,int r,int x){ if(l==r) return t[pos].sum; int mid=(l+r)>>1; if(mid>=x) return query(t[pos].ls,l,mid,x); else return query(t[pos].rs,mid+1,r,x); }
进阶
合并

int merge(int ra,int rb,int l,int r){ if(!ra) return rb; if(!rb) return ra; if(l==r){ tree[ra].sum1+=tree[rb].sum1; tree[ra].sum2+=tree[rb].sum2; tree[ra].sum3+=tree[rb].sum3; return ra; } int mid=(l+r)>>1; ls(ra)=merge(ls(ra),ls(rb),l,mid); rs(ra)=merge(rs(ra),rs(rb),mid+1,r); pushup(ra);return ra; }
吉司机
将区间对x取min,单点查询
mx区间最大值,ma区间次大值,siz区间内最大值个数(暂时不用)
1.对区间内mx<x不修改,ma<x<=mx修改mx放下标记
2.ma>=x继续递归,直到1情况

void update(int pos,int l,int r,int x,int v){ if(x>=r){ if(t[pos].mx<x) return; if(t[pos].ma<x){ t[pos].mx=t[pos].laz=v;return; } }int mid=l+r>>1;pushdown(pos); update(pos<<1,l,mid,x,v); if(x>mid) update(pos<<1|1,mid+1,r,x,v); pushup(pos); }int query(int pos,int l,int r,int x){ if(l==r) return t[pos].mx; int mid=l+r>>1;pushdown(pos); if(x<=mid) return query(pos<<1,l,mid,x); else return query(pos<<1|1,mid+1,r,x); }void pushup(int pos){ if(t[pos<<1].mx==t[pos<<1|1].mx){ t[pos].mx=t[pos<<1].mx;t[pos].siz=t[pos<<1].siz+t[pos<<1|1].siz; t[pos].ma=max(t[pos<<1].ma,t[pos<<1|1].ma);return; }if(t[pos<<1].mx>t[pos<<1|1].mx){ t[pos].mx=t[pos<<1].mx;t[pos].siz=t[pos<<1].siz; t[pos].ma=max(t[pos<<1].ma,t[pos<<1|1].mx);return; }t[pos].mx=t[pos<<1|1].mx;t[pos].siz=t[pos<<1|1].siz; t[pos].ma=max(t[pos<<1|1].ma,t[pos<<1].mx); }void pushdown(int pos){ if(t[pos].laz){ int l1=t[pos<<1].mx; if(t[pos<<1].mx>=t[pos<<1|1].mx){ t[pos<<1].mx=t[pos<<1].laz=t[pos].laz; }if(t[pos<<1|1].mx>=l1){ t[pos<<1|1].mx=t[pos<<1|1].laz=t[pos].laz; }t[pos].laz=0; } }
O(mlogn)时间复杂度分析(简单理解因为学长是这样讲的)
1是普通线段树的时间
2将分散块集成整块,1情况增多
例如对于数列 12 21 3 5 6 9 2
极限情况对2取min nlogn
2 2 2 2 2 2
对1取min O(1)
mx=2,ma=0 放下标记就跑
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律