>Link
ybtoj区间查改
luogu P3372
>解题思路
线段树的模板题,加上lazy懒标记优化
我一开始WA了,改了好久,结果发现是数组开小了我服了啊
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010
#define LL long long
using namespace std;
int n, q;
LL a[N], t[N * 5], lazy[N * 5];
void build (int k, int l, int r)
{
if (l == r)
{
t[k] = a[l];
return;
}
int mid = (l + r) / 2;
build (k * 2, l, mid);
build (k * 2 + 1, mid + 1, r);
t[k] = t[k * 2] + t[k * 2 + 1];
} //这个build可要可不要,可以直接用insert代替
void down (int k, int l, int r)
{
if (!lazy[k]) return;
t[k] += lazy[k] * (r - l + 1);
lazy[k * 2] += lazy[k];
lazy[k * 2 + 1] += lazy[k];
lazy[k] = 0;
}
void insert (int k, int l, int r, int ll, int rr, LL p)
{
down (k, l, r); //下置懒标记放在最前面
if (ll == l && r == rr)
{
lazy[k] += p;
return;
}
t[k] += p * (rr - ll + 1);
int mid = (l + r) / 2;
if (ll <= mid)
insert (k * 2, l, mid, ll, min (mid, rr), p);
if (rr > mid)
insert (k * 2 + 1, mid + 1, r, max (mid + 1, ll), rr, p);
}
LL ask (int k, int l, int r, int ll, int rr)
{
down (k, l, r);
if (ll <= l && r <= rr) return t[k];
int mid = (l + r) / 2;
LL sum = 0;
if (ll <= mid)
sum += ask (k * 2, l, mid, ll, rr);
if (rr > mid)
sum += ask (k * 2 + 1, mid + 1, r, ll, rr);
return sum;
}
int main()
{
int e, l, r, x;
scanf ("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf ("%lld", &a[i]);
build (1, 1, n);
while (q--)
{
scanf ("%d", &e);
if (e == 1)
{
scanf ("%d%d%d", &l, &r, &x);
insert (1, 1, n, l, r, x);
}
else
{
scanf ("%d%d", &l, &r);
printf ("%lld\n", ask (1, 1, n, l, r));
}
}
return 0;
}