【洛谷P3372】【模板】线段树 1

题目描述
如题,已知一个数列,你需要进行下面两种操作:

将某区间每一个数加上 kk。
求出某区间每一个数的和。
输入格式
第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:

1 x y k:将区间 [x, y][x,y] 内每个数加上 kk。
2 x y:输出区间 [x, y][x,y] 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例
输入 #1复制
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出 #1复制
11
8
20
说明/提示
对于 30%30% 的数据:n \le 8n≤8,m \le 10m≤10。
对于 70%70% 的数据:n \le {10}^3n≤10
3
,m \le {10}^4m≤10
4

对于 100%100% 的数据:1 \le n, m \le {10}^51≤n,m≤10
5

保证任意时刻数列中任意元素的和在 [-2^{63}, 2^{63})[−2
63
,2
63
) 内。

【样例解释】

【洛谷P3372】【模板】线段树 1_第1张图片

代码(lazy标记)

#include
#define ll long long
#define pa pair
const int mod = 998244353;
using namespace std;
inline int read()
{
    char ch=getchar();int f=1,x=0;
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,x,y,opt,k;
long long a[100005],sum[400005],lazy[400005];
void build(int l,int r,int p)
{
    if (l==r){sum[p]=a[l];return;}
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    sum[p]=sum[p<<1]+sum[p<<1|1];
}
void pushdown(int p,int l,int r)
{
    if (l==r) return;
    int mid=(l+r)>>1;
    lazy[p<<1]+=lazy[p];
    lazy[p<<1|1]+=lazy[p];
    sum[p<<1]+=(ll)(mid-l+1)*lazy[p];
    sum[p<<1|1]+=(ll)(r-mid)*lazy[p];
    lazy[p]=0;
}
void update(int l,int r,int x,int y,int k,int p)
{
    pushdown(p,l,r);
    if (l==x&&r==y)
    {
        lazy[p]+=k;
        sum[p]+=(ll)k*(r-l+1);
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) update(l,mid,x,y,k,p<<1);
    else if (x>mid) update(mid+1,r,x,y,k,p<<1|1);
    else update(l,mid,x,mid,k,p<<1),update(mid+1,r,mid+1,y,k,p<<1|1);
    sum[p]=sum[p<<1]+sum[p<<1|1];
}
ll query(int l,int r,int x,int y,int p)
{
    pushdown(p,l,r);
    if (l==x&&r==y) return sum[p];
    int mid=(l+r)>>1;
    if (y<=mid) return query(l,mid,x,y,p<<1);
    else if (x>mid) return query(mid+1,r,x,y,p<<1|1);
    else return query(l,mid,x,mid,p<<1)+query(mid+1,r,mid+1,y,p<<1|1);
}
int main()
{
    n=read();m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    build(1,n,1);
    for (int i=1;i<=m;i++)
    {
        int opt=read(),x=read(),y=read();
        if (opt==1)
        {
            int k=read();
            update(1,n,x,y,k,1);
        }
        else
        {
            printf("%lld\n",query(1,n,x,y,1));
        }
    }
    return 0;
}

代码(永久化标记):

#include
#include
#include
#include
#include
using namespace std;
int n,m,x,y,opt,k;
long long a[100005],sum[400005],add[400005];
void build(int l,int r,int p)
{
    if (l==r){sum[p]=a[l];return;}
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    sum[p]=sum[p<<1]+sum[p<<1|1];
}
void update(int l,int r,int x,int y,int p,int k)
{
    if (l==x&&r==y){add[p]+=k;sum[p]+=k*(r-l+1);return;}
    int mid=(l+r)>>1;
    if (y<=mid) update(l,mid,x,y,p<<1,k);
    else if (x>mid) update(mid+1,r,x,y,p<<1|1,k);
    else
    {
        update(l,mid,x,mid,p<<1,k);
        update(mid+1,r,mid+1,y,p<<1|1,k);
    }
    sum[p]=sum[p<<1]+sum[p<<1|1]+add[p]*(r-l+1);
}
long long query(int l,int r,int x,int y,int p)
{
    if (l==x&&r==y) return sum[p];
    int mid=(l+r)>>1;
    if (y<=mid) return query(l,mid,x,y,p<<1)+add[p]*(y-x+1);
    else if (x>mid) return query(mid+1,r,x,y,p<<1|1)+add[p]*(y-x+1);
    else return query(l,mid,x,mid,p<<1)+query(mid+1,r,mid+1,y,p<<1|1)+add[p]*(y-x+1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    build(1,n,1);
    while (m--)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if (opt==1)
        {
            scanf("%d",&k);
            update(1,n,x,y,1,k);
        }
        else printf("%lld\n",query(1,n,x,y,1));
    }
    return 0;
}

你可能感兴趣的:(线段树)