线段树模1

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
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值