隐藏页面特效

个人学习总结——线段树

 

 


前言

周围人都写很长一段时间的博客了,感觉自己不写,有点过不去,从今天开始试着写博客吧,so,这就是我的第一篇博客啦(/▽\)。。。


第一篇博客主要是想写一写线段树的学习和应用,以及个人的理解

一、线段树意义及作用

线段树就是一种数据结构,可以方便我们更好的查询和修改数据,日常做题的话他就是更支持数组数据的查询和修改,在竞赛方面提供更多的思考方向

二、主要操作

1.建树

建树过程我们主要采取递归建树,通过当前节点的区间向下建树,每个节点都将区间对半分下传到子节点,叶子节点是节点自身
代码如下(示例):

ll build(int z,int l,int r) { d[z].l=l,d[z].r=r; if(l==r) { d[z].sum=a[l]; return d[z].sum; } int mid=l+r>>1; d[z].sum+=(ll)build(z*2,l,mid); d[z].sum+=(ll)build(z*2+1,mid+1,r); return d[z].sum; }

2.区间修改,区间查询

单点查询就相当于l=r的区间查询,就不太用单独写出来啦

区间修改

传递懒标记,从而优化复杂度

void add(int z,int l,int r) { d[z].sum+=(ll)(r-l+1)*v; if(d[z].l==l&&d[z].r==r) { if(l!=r) d[z].p+=v; return ; } int mid=d[z].l+d[z].r>>1; if(l<=mid&&r>mid) { add(z*2,l,mid); add(z*2+1,mid+1,r); } else { if(l>mid) add(z*2+1,l,r); else add(z*2,l,r); } }

区间查询

简单查询操作

ll query(int z,int l,int r) { if(l==d[z].l&&r==d[z].r) { return d[z].sum; } ll sum=0; int mid=d[z].l+d[z].r>>1; if(d[z].p) { pushdown(z*2,d[z].p); pushdown(z*2+1,d[z].p); d[z].p=0; } if(l<=mid&&r>mid) { sum+=(ll)query(z*2,l,mid); sum+=(ll)query(z*2+1,mid+1,r); } else { if(l>mid) sum+=(ll)query(z*2+1,l,r); else sum+=(ll)query(z*2,l,r); } return sum; }

3.完整代码

代码如下:

#include<bits/stdc++.h> #define bug(a) cout<<a<<endl; #define bug2(a,b) cout<<a<<' '<<b<<endl; #define bug3(a,b,c) cout<<a<<' '<<b<<' '<<c<<endl; using namespace std; typedef long long ll; const int mod=1e9+7; const int N=1e5+10; int i,j,k,n,m,l,a[N],x,y,z,ans,v; struct node { int l,r; ll sum,p; } d[N*4]; void pushdown(int z,int p) { d[z].sum+=(ll)(d[z].r-d[z].l+1)*p; if(d[z].l!=d[z].r) d[z].p+=p; } ll build(int z,int l,int r) { d[z].l=l,d[z].r=r; if(l==r) { d[z].sum=a[l]; return d[z].sum; } int mid=l+r>>1; d[z].sum+=(ll)build(z*2,l,mid); d[z].sum+=(ll)build(z*2+1,mid+1,r); return d[z].sum; } ll query(int z,int l,int r) { if(l==d[z].l&&r==d[z].r) { return d[z].sum; } ll sum=0; int mid=d[z].l+d[z].r>>1; if(d[z].p) { pushdown(z*2,d[z].p); pushdown(z*2+1,d[z].p); d[z].p=0; } if(l<=mid&&r>mid) { sum+=(ll)query(z*2,l,mid); sum+=(ll)query(z*2+1,mid+1,r); } else { if(l>mid) sum+=(ll)query(z*2+1,l,r); else sum+=(ll)query(z*2,l,r); } return sum; } void add(int z,int l,int r) { d[z].sum+=(ll)(r-l+1)*v; if(d[z].l==l&&d[z].r==r) { if(l!=r) d[z].p+=v; return ; } int mid=d[z].l+d[z].r>>1; if(l<=mid&&r>mid) { add(z*2,l,mid); add(z*2+1,mid+1,r); } else { if(l>mid) add(z*2+1,l,r); else add(z*2,l,r); } } int main() { cin>>n>>m; for(i=1;i<=n;i++) cin>>a[i]; build(1,1,n); while(m--) { char s; cin>>s; if(s=='Q') { cin>>x>>y; ans=0; cout<<query(1,x,y)<<endl; } else { cin>>x>>y>>v; add(1,x,y); } } return 0; }

总结

以上就是个人的线段树操作总结

__EOF__

本文作者Sandust
本文链接https://www.cnblogs.com/sandust/p/18489266.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   invisible|•ω•`)  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示