来源:数据结构 —— 线段树_Alex_McAvoy的博客-CSDN博客_结构体线段树
有一说一这个东西真的有点抽象
1.建树
存储方式:结构体
要素:左端点,右端点,要维护的信息,懒标记
(1)每个节点的左孩子区间范围为[l,mid],右孩子为[mid+1,r]
(2)对于结点k,左孩子结点为2*k,右孩子为2*k+1
(3)左右区间端点相等,是叶子结点
结构体形式:
typedef struct node
{
int l,r;
int w;
int mark;
}Tree[n<<2];
Tree tree;
建立过程:
void build(int l,int r,int k)
{
tree[k].l=l;
tree[k].r=r;
if(l==r)
{
scanf("%d",&tree[k].w);
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
2.查询端点
int ans1;
void querythenode(int k,int x)
{
if(tree[k].l==tree[k].r)
{
ans1=tree[k].w;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(x>=mid)
{
querythenode(k<<1|1,x);
}
else
{
querythenode(k<<1,x);
}
}
3.单点修改(加法)
自顶向下查询所有需求的区间,再自底向上修改
void modifythenode(int k,int x,int v)
{
if(tree[k].l==tree[k].r)
{
tree[x].w+=v;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(x>=mid)
{
modifythenode(k<<1|1,x,v);
}
else
{
modifythenode(k<<1,x,v);
}
tree[k].w=tree[k<<1].w+tree[k<<|1].w;
}
4.区间查询(未修改)
(图片来自 Alex_McAvoy的博客)
int ans2=0;
void querytheinterval(int k,int x,int y)
{
if(x>=tree[k].l&&y<=tree[k]r)
{
ans+=tree[k].w;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(x<=mid)
{
querytheinterval(k<<1,x,y);
}
if(y>=mid)
{
querytheinterval(k<<1|1,x,y);
}
}
5.区间修改
lazy tag(摘自木子喵neko的视频【neko】线段树【算法编程#6】_哔哩哔哩_bilibili):
将此区间标记,意思是这个区间的值已经更新,但它的子区间还没有更新,更新的信息就是标记里存的值
1.判断覆盖并打标记。如果要修改的区间完全覆盖当前区间,直接更新这个区间,打上lazy标记
2.下传清零。如果没有完全覆盖,且当前区间有lazy标记,下传lazy标记到子区间,再清除当前区间的lazy标记
3.递归左右。如果修改区间和左儿子有交集,搜索左儿子;与右儿子有交集,搜索右儿子
4.合并更新。最后将当前区间的值更新
6.区间查询(修改后)
1.如果要查询的区间完全覆盖当前区间,直接返回当前区间的值
2.如果没有完全覆盖,下传lazy标记
3.交左搜左,交右搜右
4.合并更新
板子题P3372(非结构体AC代码)
#include<stdio.h>
long a[1000000];
long ans[4000000];
long tag[4000000];
void pushup(long p)
{
ans[p]=ans[p<<1]+ans[p<<1|1];
}
void pushdown(long p,long l,long r,long k)
{
long mid=(l+r)>>1;
tag[p<<1]+=k;
ans[p<<1]+=(mid-l+1)*k;
tag[p<<1|1]+=k;
ans[p<<1|1]+=(r-mid)*k;
tag[p]=0;
}
void build(long p,long l,long r)
{
tag[p]=0;
if(l==r)
{
ans[p]=a[l];
return;
}
long mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void update(long l,long r,long x,long y,long k,long p)
{
if(x<=l&&y>=r)
{
tag[p]+=k;
ans[p]+=(r-l+1)*k;
return;
}
pushdown(p,l,r,tag[p]);
long mid=(l+r)>>1;
if(x<=mid) update(l,mid,x,y,k,p<<1);
if(y>mid) update(mid+1,r,x,y,k,p<<1|1);
pushup(p);
}
long sumq(long p,long l,long r,long x,long y)
{
long res=0;
if(x<=l&&y>=r)
{
return ans[p];
}
pushdown(p,l,r,tag[p]);
long mid=(l+r)>>1;
if(x<=mid) res+=sumq(p<<1,l,mid,x,y);
if(y>mid) res+=sumq(p<<1|1,mid+1,r,x,y);
return res;
}
int main()
{
long n,m;
scanf("%ld %ld",&n,&m);
long i;
for(i=1;i<=n;i++)
{
scanf("%ld",&a[i]);
}
build(1,1,n);
for(i=1;i<=m;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
long x,y,k;
scanf("%ld %ld %ld",&x,&y,&k);
update(1,n,x,y,k,1);
}
if(op==2)
{
long x2,y2,temp;
scanf("%ld %ld",&x2,&y2);
temp=sumq(1,1,n,x2,y2);
printf("%ld\n",temp);
}
}
return 0;
}
板子题P3373
#include<stdio.h>
#include<stdlib.h>
long ans[4000000];
long add[4000000];
long mul[4000000];
long a[1000000];
long mod;
void pushup(long p)
{
ans[p]=(ans[p<<1]+ans[p<<1|1])%mod;
}
void pushdown(long p,long l,long r)
{
long mid=(l+r)>>1;
ans[p<<1]=(ans[p<<1]*mul[p]+add[p]*(mid-l+1))%mod;
ans[p<<1|1]=(ans[p<<1|1]*mul[p]+add[p]*(r-mid))%mod;
mul[p<<1]=(mul[p<<1]*mul[p])%mod;
mul[p<<1|1]=(mul[p<<1|1]*mul[p])%mod;
add[p<<1]=(add[p<<1]*mul[p]+add[p])%mod;
add[p<<1|1]=(add[p<<1|1]*mul[p]+add[p])%mod;
add[p]=0;
mul[p]=1;
}
void build(long l,long r,long p)
{
mul[p]=1;
add[p]=0;
if(l==r)
{
ans[p]=a[l]%mod;
return;
}
long mid=(l+r)>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
pushup(p);
}
void update1(long l,long r,long x,long y,long k,long p)
{
if(l>=x&&r<=y)
{
add[p]=(add[p]+k)%mod;
ans[p]=(ans[p]+(r-l+1)*k)%mod;
return;
}
pushdown(p,l,r);
long mid=(l+r)>>1;
if(x<=mid) update1(l,mid,x,y,k,p<<1);
if(y>mid) update1(mid+1,r,x,y,k,p<<1|1);
pushup(p);
}
void update2(long l,long r,long x,long y,long k,long p)
{
if(l>=x&&r<=y)
{
ans[p]=(ans[p]*k)%mod;
mul[p]=(mul[p]*k)%mod;
add[p]=(add[p]*k)%mod;
return;
}
pushdown(p,l,r);
long mid=(l+r)>>1;
if(x<=mid) update2(l,mid,x,y,k,p<<1);
if(y>mid) update2(mid+1,r,x,y,k,p<<1|1);
pushup(p);
}
long sumq(long l,long r,long x,long y,long p)
{
long res=0;
if(l>=x&&r<=y)
{
return ans[p];
}
pushdown(p,l,r);
long mid=(l+r)>>1;
if(x<=mid) res=(res+sumq(l,mid,x,y,p<<1))%mod;
if(y>mid) res=(res+sumq(mid+1,r,x,y,p<<1|1))%mod;
return res;
}
int main()
{
long n,m;
scanf("%ld %ld %ld",&n,&m,&mod);
long i;
for(i=1;i<=n;i++)
{
scanf("%ld",&a[i]);
}
build(1,n,1);
for(i=1;i<=m;i++)
{
long x,y,k;
int op;
scanf("%d",&op);
if(op==1)
{
scanf("%ld %ld %ld",&x,&y,&k);
update2(1,n,x,y,k,1);
}
if(op==2)
{
scanf("%ld %ld %ld",&x,&y,&k);
update1(1,n,x,y,k,1);
}
if(op==3)
{
long temp;
scanf("%ld %ld",&x,&y);
temp=sumq(1,n,x,y,1);
printf("%ld\n",temp);
}
}
return 0;
}
离散化