个人学习总结——线段树
文章目录
前言
周围人都写很长一段时间的博客了,感觉自己不写,有点过不去,从今天开始试着写博客吧,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;
}