线段树小记
Posted gk0328
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树小记相关的知识,希望对你有一定的参考价值。
普通线段树可以[先标记(tag)后更改]或[边推(tag)边更改]
打算从原来的[先标记(tag)后更改]改变为较为普及的[边推(tag)边更改]
这里放模板题代码
#include<cstdio>
#include<iostream>
#define N 100005
#define ll long long
using namespace std;
struct node
{
int l,r;
ll s,lz;
}t[N << 2];
ll a[N];
int n,m,opt,x,y;
ll z;
void merge(int p)
{
t[p].s=t[p+p].s+t[p+p+1].s;
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if (l==r)
{
t[p].s=a[l];
t[p].lz=0;
return;
}
int mid=(l+r) >> 1;
build(p+p,l,mid);
build(p+p+1,mid+1,r);
merge(p);
}
void down_tag(int p,ll z)
{
t[p].s+=z*(t[p].r-t[p].l+1);
t[p].lz+=z;
}
void down(int p)
{
down_tag(p+p,t[p].lz),down_tag(p+p+1,t[p].lz);
t[p].lz=0;
}
void change(int p,int x,int y,ll z)
{
if (t[p].l>y||t[p].r<x)
return;
if (t[p].l>=x&&t[p].r<=y)
{
t[p].s+=z*(t[p].r-t[p].l+1);
t[p].lz+=z;
return;
}
down(p);
change(p+p,x,y,z);
change(p+p+1,x,y,z);
merge(p);
}
ll calc(int p,int x,int y)
{
if (t[p].l>y||t[p].r<x)
return 0;
if (t[p].l>=x&&t[p].r<=y)
return t[p].s;
down(p);
return calc(p+p,x,y)+calc(p+p+1,x,y);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
for (int i=1;i<=m;i++)
{
scanf("%d",&opt);
switch (opt)
{
case 1:
scanf("%d%d%lld",&x,&y,&z);
change(1,x,y,z);
break;
case 2:
scanf("%d%d",&x,&y);
printf("%lld
",calc(1,x,y));
break;
}
}
}
以上是关于线段树小记的主要内容,如果未能解决你的问题,请参考以下文章