https://www.luogu.com.cn/problem/P3372
修改版,i<<1 和 i<<1|1 太容易写错了
define 好了再使用吧
23 :27 修改版:
#include <iostream>
using namespace std;
#define ll long long
#define ls (i<<1)
#define rs (i<<1|1)
const int N = 1e5 + 10;
struct Node {
int l, r;
ll data, lz;
}tr[N<<2];
ll input[N];
inline void pushup(int i)
{
tr[i].data = tr[ls].data + tr[rs].data;
}
void build(int i, int l, int r)
{
tr[i].l = l, tr[i].r = r;
if(l == r)
{
tr[i].data = input[l];
return ;
}
int mid = (l+r) >> 1;
build(ls, l, mid); // 注意这里的分隔:mid
build(rs, mid+1, r);
pushup(i);
}
inline void push_down(int i) // 传递懒标记
{
if(tr[i].lz != 0)
{
tr[ls].lz += tr[i].lz; //左右儿子分别加上父亲的lz
tr[rs].lz += tr[i].lz;
int mid = (tr[i].l + tr[i].r) >> 1;
tr[ls].data += tr[i].lz*(mid-tr[ls].l+1); // l ~ mid
// 所以将 lz 传递给孩子节点时,孩子节点的值要加上区间长度乘以lz值
tr[rs].data += tr[i].lz*(tr[rs].r-mid); // mid+1 ~ r
tr[i].lz = 0;
}
return ;
}
inline void update(int i, int l, int r, ll k)
{
if(tr[i].r <= r and tr[i].l >= l)
{
tr[i].data += k*(tr[i].r - tr[i].l + 1);
tr[i].lz += k;
return ;
}
push_down(i);
if(tr[ls].r >= l) update(ls,l,r,k);
if(tr[rs].l <= r) update(rs,l,r,k);
pushup(i);
return ;
}
inline ll ask(int i, int l, int r)
{
if(tr[i].l >= l and tr[i].r <= r)
return tr[i].data;
if(tr[i].r < l or tr[i].l > r) return 0;
push_down(i);
ll res = 0;
if(tr[ls].r >= l) res += ask(ls,l,r);
if(tr[rs].l <= r) res += ask(rs,l,r);
return res;
}
int main()
{
int n, m;
cin >> n >> m;
for(int i=1; i<=n; i++)
scanf("%lld", &input[i]);
build(1,1,n);
while(m--)
{
int op, l, r;
ll k;
scanf("%d %d %d",&op,&l,&r);
if(op==1)
{
scanf("%lld", &k);
update(1,l,r,k);
}
else printf("%lld\n", ask(1,l,r));
}
return 0;
}
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
#define ll long long
struct Node{
int l, r;
ll data, lz;
}tr[N<<2];
ll input[N];
inline void pushup(int i)
{
tr[i].data = tr[i<<1].data + tr[i<<1|1].data;
}
void build(int i, int l, int r) // 建树
{
tr[i].l = l, tr[i].r = r;
if(l == r)
{
tr[i].data = input[l];
return ;
}
int mid = (l+r) >> 1;
build(i<<1, l, mid); build(i<<1|1, mid+1, r);
pushup(i);
}
inline void push_down(int i) // 传递懒标记
{
if(tr[i].lz!=0)
{
tr[i*2].lz += tr[i].lz; //左右儿子分别加上父亲的lz
tr[i*2+1].lz += tr[i].lz;
int mid = (tr[i].l+tr[i].r)/2;
tr[i*2].data += tr[i].lz*(mid-tr[i*2].l+1); // l ~ mid
// 所以将 lz 传递给孩子节点时,孩子节点的值要加上区间长度乘以lz值
tr[i*2+1].data += tr[i].lz*(tr[i*2+1].r-mid); // mid+1 ~ r
tr[i].lz=0; //父亲lz归零
}
return ;
}
inline void update(int i, int l, int r, ll k)
{
// 如果当前区间被完全覆盖在目标区间里,
// 将这个区间的sum+k*(tr[i].r-tr[i].l+1)
if(tr[i].r <= r and tr[i].l >= l)
{
tr[i].data += k*(tr[i].r - tr[i].l+1); // 这个区间
tr[i].lz += k; //记录lazytage,下次直接加上
return ;
}
push_down(i); // 向下传递懒标记 再 向下递归修改
if(tr[i<<1].r >= l) update(i<<1,l,r,k);
if(tr[i<<1|1].l <= r) update(i<<1|1,l,r,k);
pushup(i);
return ;
}
inline ll ask(int i, int l, int r){ // 线段树询问操作
if(tr[i].l>=l && tr[i].r<=r)
return tr[i].data;
if(tr[i].r<l || tr[i].l>r) return 0;
push_down(i); // 向下传递懒标记,然后再统计
ll res = 0;
if(tr[i*2].r>=l) res += ask(i<<1,l,r);
if(tr[i*2+1].l<=r) res += ask(i<<1|1,l,r);
return res ;
}
int main()
{
int n, m;
scanf("%d %d",&n, &m);
for(int i = 1; i <= n; i++)
scanf("%lld", &input[i]);
build(1, 1, n);
while(m--)
{
int op,l,r; scanf("%d",&op);
if(op==1)
{
ll k;
scanf("%d %d %lld", &l, &r, &k);
update(1, l, r, k);
}else{
scanf("%d %d", &l, &r);
printf("%lld\n", ask(1, l, r));
}
}
return 0;
}
/* input
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
*/
/* ans
11
8
20
*/