线段树

NOIP阶段只要不涉及区间翻转、区间插入的序列问题都可以用线段树实现。

每一个节点维护一个区间的信息。

线段树有分治的感觉。

线段树可以处理很多符合结合律的操作。

时间复杂度,建树为O(n),区间查询和区间修改为O(log n)

空间要开原序列长度的四倍。

查询的话就是序列分割,由于分割次数近似log n,故总复杂度为O(n log n)

code:

void pushup(int cur) { val[cur]=val[ls[cur]]+val[rs[cur]]; } void pushdown(int cur,int l,int r) { if(!lazy[cur]) return; lazy[ls[cur]]+=lazy[cur]; lazy[rs[cur]]+=lazy[cur]; int mid=(l+r)>>1; val[ls[cur]]+=lazy[cur]*(mid-l+1); val[rs[cur]]+=lazy[cur]*(r-mid); lazy[cur]=0; } void build(int L,int R,int &cur) { cur=++tree_cnt; if(L==R) { val[cur]=a[L]; return; } int mid=(L+R)>>1; build(L,mid,ls[cur]); build(mid+1,R,rs[cur]); pushup(cur); } void modify(int L,int R,int l,int r,ll add,int cur) { if(L<=l&&R>=r) { val[cur]+=add*(r-l+1); lazy[cur]+=add; return; } pushdown(cur,l,r); int mid=(l+r)>>1; if(L<=mid) modify(L,R,l,mid,add,ls[cur]); if(R>mid) modify(L,R,mid+1,r,add,rs[cur]); pushup(cur); } ll query(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return val[cur]; pushdown(cur,l,r); ll sum=0; int mid=(l+r)>>1; if(L<=mid) sum+=query(L,R,l,mid,ls[cur]); if(R>mid) sum+=query(L,R,mid+1,r,rs[cur]); return sum; } ...... build(1,n,root);//建树 modify(x,y,1,n,z,root);//区间修改,x到y的区间加上z query(x,y,1,n,root)//区间查询,x到y的和

动态开点

code:

void pushup(int cur) { val[cur]=val[ls[cur]]+val[rs[cur]]; } void pushdown(int cur,int l,int r) { if(!lazy[cur]) return; int mid=(l+r)>>1; if(!ls[cur]) ls[cur]=++tree_cnt; lazy[ls[cur]]+=lazy[cur]; val[ls[cur]]+=lazy[cur]*(mid-l+1); if(!rs[cur]) rs[cur]=++tree_cnt; lazy[rs[cur]]+=lazy[cur]; val[rs[cur]]+=lazy[cur]*(r-mid); lazy[cur]=0; } void modify(int L,int R,int l,int r,ll add,int &cur) { if(!cur) cur=++tree_cnt; if(L<=l&&R>=r) { val[cur]+=add*(r-l+1); lazy[cur]+=add; return; } pushdown(cur,l,r); int mid=(l+r)>>1; if(L<=mid) modify(L,R,l,mid,add,ls[cur]); if(R>mid) modify(L,R,mid+1,r,add,rs[cur]); pushup(cur); } ll query(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return val[cur]; pushdown(cur,l,r); ll sum=0; int mid=(l+r)>>1; if(L<=mid) sum+=query(L,R,l,mid,ls[cur]); if(R>mid) sum+=query(L,R,mid+1,r,rs[cur]); return sum; }

线段树合并

xy合并为x

通常用来合并权值线段树(一个节点权值为其值域区间元素个数)

更新信息时要特判叶子节点的情况,防止信息覆盖,代码为雨天的尾巴

code:

int merge(int x,int y,int l,int r) { if(!x||!y) return x+y; int p=++tree_cnt; if(l==r) ma[p]=ma[x]+ma[y],id[p]=l; else { ls[p]=merge(ls[x],ls[y],l,mid); rs[p]=merge(rs[x],rs[y],mid+1,r); pushup(p); } return p; }

线段树分裂

code:

void pushup(int cur) { cnt[cur]=cnt[ls[cur]]+cnt[rs[cur]]; } void modify(int l,int r,int pos,int v,int &cur) { if(!cur) cur=++tot; if(l==r) { cnt[cur]+=v; return; } if(pos<=mid) modify(l,mid,pos,v,ls[cur]); else modify(mid+1,r,pos,v,rs[cur]); pushup(cur); } int query(int L,int R,int l,int r,int cur) { if(!cur) return 0; if(L<=l&&R>=r) return cnt[cur]; int v=0; if(L<=mid) v+=query(L,R,l,mid,ls[cur]); if(R>mid) v+=query(L,R,mid+1,r,rs[cur]); return v; } int kth(int l,int r,int k,int cur) { if(l==r) return l; if(cnt[ls[cur]]>=k) return kth(l,mid,k,ls[cur]); else return kth(mid+1,r,k-cnt[ls[cur]],rs[cur]); } int merge(int x,int y) { if(!x||!y) return x+y; int p=++tot; cnt[p]=cnt[x]+cnt[y]; ls[p]=merge(ls[x],ls[y]); rs[p]=merge(rs[x],rs[y]); return p; } void split(int L,int R,int l,int r,int &x,int &y) { if(!x) return; if(L<=l&&R>=r) { y=x,x=0; return; } y=++tot; if(L<=mid) split(L,R,l,mid,ls[x],ls[y]); if(R>mid) split(L,R,mid+1,r,rs[x],rs[y]); pushup(x),pushup(y); }

线段树优化建图

code:

void build_in(int L,int R,int &cur) { cur=++tree_cnt; if(L==R) { in_num[L]=cur; return; } int mid=(L+R)>>1; build_in(L,mid,ls[cur]); build_in(mid+1,R,rs[cur]); add(ls[cur],cur,0),add(rs[cur],cur,0); } void build_out(int L,int R,int &cur) { cur=++tree_cnt; if(L==R) { out_num[L]=cur; return; } int mid=(L+R)>>1; build_out(L,mid,ls[cur]); build_out(mid+1,R,rs[cur]); add(cur,ls[cur],0),add(cur,rs[cur],0); } void modify_in(int L,int R,int l,int r,int pos,int val,int &cur) { if(L<=l&&R>=r) { add(cur,pos,val); return; } int mid=(l+r)>>1; if(L<=mid) modify_in(L,R,l,mid,pos,val,ls[cur]); if(R>mid) modify_in(L,R,mid+1,r,pos,val,rs[cur]); } void modify_out(int L,int R,int l,int r,int pos,int val,int &cur) { if(L<=l&&R>=r) { add(pos,cur,val); return; } int mid=(l+r)>>1; if(L<=mid) modify_out(L,R,l,mid,pos,val,ls[cur]); if(R>mid) modify_out(L,R,mid+1,r,pos,val,rs[cur]); }

线段树分治

维护时间区间,对询问的时间轴进行分治,每个修改操作会有一个作用的区间,将修改标记到线段树上,dfs一遍线段树来统计答案

连通图:删去无向连通图一些边后,询问原图是否连通

将删边转化为边存在的区间,用带权并查集维护连通块大小

code:

void build(int l,int r,int &cur) { if(!cur) cur=++tree_cnt; if(l==r) return; int mid=(l+r)>>1; build(l,mid,ls[cur]); build(mid+1,r,rs[cur]); } void insert(int L,int R,int l,int r,int id,int cur) { if(L<=l&&R>=r) { v[cur].push_back(id); return; } int mid=(l+r)>>1; if(L<=mid) insert(L,R,l,mid,id,ls[cur]); if(R>mid) insert(L,R,mid+1,r,id,rs[cur]); } int find(int x) { return fa[x]==x?x:find(fa[x]); } void merge(int x,int y) { int rx=find(x),ry=find(y); if(rx==ry) return; if(de[rx]<de[ry]) swap(rx,ry); st[++top]=(node){rx,ry,de[rx]}; fa[ry]=rx,siz[rx]+=siz[ry]; de[rx]=max(de[rx],de[ry]+1); } void del(int id) { int x=st[id].x,y=st[id].y; fa[y]=y,siz[x]-=siz[y],de[x]=st[id].deep; } void dfs(int l,int r,int cur) { int now=top,size=v[cur].size(); for(int i=0;i<size;++i) merge(e[v[cur][i]].x,e[v[cur][i]].y); if(l==r) ans[l]=(siz[find(1)]==n); else { int mid=(l+r)>>1; dfs(l,mid,ls[cur]),dfs(mid+1,r,rs[cur]); } while(top>now) del(top--); }

Shortest Path Queries:维护一个无向连通图,边有边权,支持加边删边和询问从xy的异或最短路

code:

void build(int l,int r,int &cur) { if(!cur) cur=++tree_cnt; if(l==r) return; int mid=(l+r)>>1; build(l,mid,ls[cur]); build(mid+1,r,rs[cur]); } void insert(int L,int R,int l,int r,int id,int cur) { if(L<=l&&R>=r) { v[cur].push_back(id); return; } int mid=(l+r)>>1; if(L<=mid) insert(L,R,l,mid,id,ls[cur]); if(R>mid) insert(L,R,mid+1,r,id,rs[cur]); } void ins(int x,int cur) { for(int i=30;i>=0;--i) { if(x&(1<<i)) { if(!a[cur][i]) { a[cur][i]=x; break; } else x^=a[cur][i]; } } } int get(int x,int cur) { for(int i=30;i>=0;--i) if((x^a[cur][i])<x) x^=a[cur][i]; return x; } int find(int x) { return fa[x]==x?x:find(fa[x]); } int xor_dis(int x) { return fa[x]==x?dis[x]:dis[x]^xor_dis(fa[x]); } void merge(int x,int y,int v) { if(de[x]<de[y]) swap(x,y); st[++top]=(node){x,y,de[x]}; fa[y]=x,dis[y]=v,de[x]=max(de[x],de[y]+1); } void del(int id) { int x=st[id].x,y=st[id].y; fa[y]=y,dis[y]=0,de[x]=st[id].deep; } void copy(int x,int y) { for(int i=0;i<=30;++i) a[y][i]=a[x][i]; } void dfs(int l,int r,int cur) { int now=top,size=v[cur].size(); for(int i=0;i<size;++i) { int id=v[cur][i],x=e[id].x,y=e[id].y,v=e[id].v; v^=xor_dis(x)^xor_dis(y),x=find(x),y=find(y); if(x==y) ins(v,cur); else merge(x,y,v); } if(l==r) { int x=qu[l].x,y=qu[l].y; ans[l]=get(xor_dis(x)^xor_dis(y),cur); } else { int mid=(l+r)>>1; copy(cur,ls[cur]),dfs(l,mid,ls[cur]); copy(cur,rs[cur]),dfs(mid+1,r,rs[cur]); } while(top>now) del(top--); }

李超线段树

用来维护坐标系上的线段,支持添加线段和询问

每个线段树上每个区间维护一个优势线段,其至少覆盖了该区间的一半,维护时分类讨论即可

Blue Mary开公司

code:

double y(int id,int x) { return k[id]*(x-1)+b[id]; } void modify(int l,int r,int id,int &cur) { if(!cur) cur=++tree_cnt; if(y(id,l)>y(val[cur],l)&&y(id,r)>y(val[cur],r)) { val[cur]=id; return; } if(y(id,l)<=y(val[cur],l)&&y(id,r)<=y(val[cur],r)) return; int mid=(l+r)>>1; if(k[id]>k[val[cur]]) { if(y(id,mid)>y(val[cur],mid)) modify(l,mid,val[cur],ls[cur]),val[cur]=id; else modify(mid+1,r,id,rs[cur]); } else { if(y(id,mid)>y(val[cur],mid)) modify(mid+1,r,val[cur],rs[cur]),val[cur]=id; else modify(l,mid,id,ls[cur]); } } double query(int l,int r,int x,int cur) { if(l==r) return y(val[cur],x); int mid=(l+r)>>1; double ans=y(val[cur],x); if(x<=mid) return max(ans,query(l,mid,x,ls[cur])); else return max(ans,query(mid+1,r,x,rs[cur])); }

Segment

code:

double y(int id,int x) { return k[id]*x+b[id]; } bool check(int a,int b,int x) { return fabs(y(a,x)-y(b,x))>eps?y(a,x)<y(b,x):a>b; } void modify(int L,int R,int l,int r,int id,int &cur) { if(!cur) cur=++tree_cnt; int mid=(l+r)>>1; if(L<=l&&R>=r) { if(check(id,val[cur],l)&&check(id,val[cur],r)) return; if(!check(id,val[cur],l)&&!check(id,val[cur],r)) { val[cur]=id; return; } if(!check(id,val[cur],mid)) swap(id,val[cur]); if(!check(id,val[cur],l)) modify(L,R,l,mid,id,ls[cur]); else modify(L,R,mid+1,r,id,rs[cur]); return; } if(L<=mid) modify(L,R,l,mid,id,ls[cur]); if(R>mid) modify(L,R,mid+1,r,id,rs[cur]); } int query(int l,int r,int x,int cur) { if(l==r) return val[cur]; int mid=(l+r)>>1,ans; if(x<=mid) ans=query(l,mid,x,ls[cur]); else ans=query(mid+1,r,x,rs[cur]); if(check(ans,val[cur],x)) ans=val[cur]; return ans; }

吉司机线段树

【模板】线段树 3

code:

void pushup(int cur) { sum[cur]=sum[ls]+sum[rs],ma[cur]=max(ma[ls],ma[rs]),hma[cur]=max(hma[ls],hma[rs]); if(ma[ls]==ma[rs]) se[cur]=max(se[ls],se[rs]),cnt[cur]=cnt[ls]+cnt[rs]; else if(ma[ls]>ma[rs]) se[cur]=max(se[ls],ma[rs]),cnt[cur]=cnt[ls]; else se[cur]=max(ma[ls],se[rs]),cnt[cur]=cnt[rs]; } void pushtag(int cur,int l,int r,ll v,ll hv,ll w,ll hw) { sum[cur]+=v*cnt[cur]+w*(r-l+1-cnt[cur]); hma[cur]=max(hma[cur],ma[cur]+hv),ma[cur]+=v; htag[cur]=max(htag[cur],tag[cur]+hv),tag[cur]+=v; hadd[cur]=max(hadd[cur],add[cur]+hw),add[cur]+=w; if(se[cur]!=-inf) se[cur]+=w; } void pushdown(int cur,int l,int r) { ll maxv=max(ma[ls],ma[rs]); if(ma[ls]==maxv) pushtag(ls,l,mid,tag[cur],htag[cur],add[cur],hadd[cur]); else pushtag(ls,l,mid,add[cur],hadd[cur],add[cur],hadd[cur]); if(ma[rs]==maxv) pushtag(rs,mid+1,r,tag[cur],htag[cur],add[cur],hadd[cur]); else pushtag(rs,mid+1,r,add[cur],hadd[cur],add[cur],hadd[cur]); tag[cur]=htag[cur]=add[cur]=hadd[cur]=0; } void build(int l,int r,int cur) { if(l==r) { sum[cur]=ma[cur]=hma[cur]=a[l],se[cur]=-inf,cnt[cur]=1; return; } build(l,mid,ls),build(mid+1,r,rs),pushup(cur); } void modify_add(int L,int R,int l,int r,ll v,int cur) { if(L<=l&&R>=r) { pushtag(cur,l,r,v,v,v,v); return; } pushdown(cur,l,r); if(L<=mid) modify_add(L,R,l,mid,v,ls); if(R>mid) modify_add(L,R,mid+1,r,v,rs); pushup(cur); } void modify_min(int L,int R,int l,int r,ll v,int cur) { if(v>=ma[cur]) return; if(L<=l&&R>=r&&v>se[cur]) { pushtag(cur,l,r,v-ma[cur],v-ma[cur],0,0); return; } pushdown(cur,l,r); if(L<=mid) modify_min(L,R,l,mid,v,ls); if(R>mid) modify_min(L,R,mid+1,r,v,rs); pushup(cur); } ll query_sum(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return sum[cur]; pushdown(cur,l,r); ll ans=0; if(L<=mid) ans+=query_sum(L,R,l,mid,ls); if(R>mid) ans+=query_sum(L,R,mid+1,r,rs); return ans; } ll query_max(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return ma[cur]; pushdown(cur,l,r); ll ans=-inf; if(L<=mid) ans=max(ans,query_max(L,R,l,mid,ls)); if(R>mid) ans=max(ans,query_max(L,R,mid+1,r,rs)); return ans; } ll query_his(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return hma[cur]; pushdown(cur,l,r); ll ans=-inf; if(L<=mid) ans=max(ans,query_his(L,R,l,mid,ls)); if(R>mid) ans=max(ans,query_his(L,R,mid+1,r,rs)); return ans; }

CPU监控

code:

void pushup(int cur) { ma[cur]=max(ma[ls],ma[rs]),hma[cur]=max(hma[ls],hma[rs]); } void pushadd(int cur,ll v,ll hv) { hma[cur]=max(hma[cur],ma[cur]+hv),ma[cur]+=v; if(!tag[cur]) hadd[cur]=max(hadd[cur],add[cur]+hv),add[cur]+=v; else hcov[cur]=max(hcov[cur],cov[cur]+hv),cov[cur]+=v; } void pushcov(int cur,ll v,ll hv) { tag[cur]=1; hma[cur]=max(hma[cur],hv),ma[cur]=v; hcov[cur]=max(hcov[cur],hv),cov[cur]=v; } void pushdown(int cur) { if(add[cur]) pushadd(ls,add[cur],hadd[cur]),pushadd(rs,add[cur],hadd[cur]); if(tag[cur]) pushcov(ls,cov[cur],hcov[cur]),pushcov(rs,cov[cur],hcov[cur]); add[cur]=hadd[cur]=tag[cur]=cov[cur]=hcov[cur]=0; } void build(int l,int r,int cur) { if(l==r) { ma[cur]=hma[cur]=a[l]; return; } build(l,mid,ls),build(mid+1,r,rs),pushup(cur); } void modify_add(int L,int R,int l,int r,ll v,int cur) { if(L<=l&&R>=r) { pushadd(cur,v,v); return; } pushdown(cur); if(L<=mid) modify_add(L,R,l,mid,v,ls); if(R>mid) modify_add(L,R,mid+1,r,v,rs); pushup(cur); } void modify_cov(int L,int R,int l,int r,ll v,int cur) { if(L<=l&&R>=r) { pushcov(cur,v,v); return; } pushdown(cur); if(L<=mid) modify_cov(L,R,l,mid,v,ls); if(R>mid) modify_cov(L,R,mid+1,r,v,rs); pushup(cur); } ll query_max(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return ma[cur]; pushdown(cur); ll ans=-inf; if(L<=mid) ans=max(ans,query_max(L,R,l,mid,ls)); if(R>mid) ans=max(ans,query_max(L,R,mid+1,r,rs)); return ans; } ll query_his(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return hma[cur]; pushdown(cur); ll ans=-inf; if(L<=mid) ans=max(ans,query_his(L,R,l,mid,ls)); if(R>mid) ans=max(ans,query_his(L,R,mid+1,r,rs)); return ans; }

__EOF__

本文作者lhm_
本文链接https://www.cnblogs.com/lhm-/p/12229433.html
关于博主:sjzez 的一名 OI 学生
版权声明:转载标明出处
声援博主:希望得到宝贵的建议
posted @   lhm_liu  阅读(261)  评论(1编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示