线段树 P3372

题目描述

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

  1. 将某区间每一个数加上 kk。
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。

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

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

  1. 1 x y k:将区间 [x, y][x,y] 内每个数加上 kk。
  2. 2 x y:输出区间 [x, y][x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例

输入

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

输出

11

8

20

代码

#include<iostream>
#include<cstdio>
using namespace std;
long long a[100001], c[100001],sum[100001];
int n, m;
long long  lowbit(long long x)
{
    return x&(-x);
}
void update(long long i, long long k)
{
    long long x = i;
    while (i <= n)
    {
        c[i] += k;
        sum[i] += (x-1)*k;
        i += lowbit(i);
    }
}
long long getsum(long long i)
{
    long long res = 0;
    long long x = i;
    while (i > 0)
    {
        res += c[i]*x-sum[i];
        i -= lowbit(i);
    }
    return res;
}
int main()
{
    long long type,x,y,k;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
        update(i, a[i]-a[i-1]);
    }
    for (int i = 0; i < m; i++)
    {
        scanf("%lld %lld %lld", &type,&x,&y);
        if (type == 1)
        {
            scanf("%lld", &k);
            update(x, k);
            update(y + 1, -k);
        }
        else
        {
            printf("%lld\n", getsum(y) - getsum(x - 1));
        }
    }
}

开始int 溢出,改为long long通过

猜你喜欢

转载自www.cnblogs.com/Jason66661010/p/12820946.html