wls线段树板子(区间修改+区间查询)

题目链接:P3372 【模板】线段树 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

视频链接:这可能是全b站最通俗易懂的线段树入门教学视频了 P2 带标记的线段树_哔哩哔哩_bilibili

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, m, a[100001], f[400001], v[400001];

void buildtree(int k, int l, int r){    //建树,k为当前点的标号,l区间左端点,r区间右端点
	if(l == r){    //走到底 
		f[k] = a[l];
		return;
	}
	int m = (l + r) >> 1;    
	buildtree(k + k, l, m);    //建左子树
	buildtree(k + k + 1, m + 1, r);    //建右子树
	f[k] =  f[k + k] + f[k + k + 1];    //该点的值为左子树和右子树的和
}

void insert(int k, int l, int r, int x, int y, int z){    //k为当前点的标号,l区间左端点,r区间右端点,在x-y这个区间加上z 
	if(l == x && r == y){    //区间重合 
		v[k] += z;
		return;
	}
	f[k] += (y - x + 1) * z;    //区间长度乘上z 
	int m = (l + r) >> 1;
	if(y <= m)    //s-t完全坐落在左区间
		insert(k + k, l, m, x, y, z); 
	else{
		if(x > m)    //完全坐落在右区间 
			insert(k + k + 1, m + 1, r, x, y, z);
		else{    //横跨两边 
			insert(k + k, l, m, x, m, z);
			insert(k + k + 1, m + 1, r, m + 1, y, z);
		}
	}
}

int calc(int k, int l, int r, int x, int y, int p){    //k为下标,求区间l-r中x-y的和, p为根到当前结点v的和(不包括当前的点) 
	p += v[k];
	if(l == x && r == y)    //区间重合 
		return p * (r - l + 1) + f[k];
	int m = (l + r) >> 1; 
	if(y <= m)    //s-t完全坐落在左区间
		return calc(k + k, l, m, x, y, p); 
	else{
		if(x > m)    //完全坐落在右区间 
			return calc(k + k + 1, m + 1, r, x, y, p);
		else    //横跨两边 
			return 	calc(k + k, l, m, x, m, p) + calc(k + k + 1, m + 1, r, m + 1, y, p);
	}
} 

signed main(){
	scanf("%lld%lld", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	buildtree(1, 1, n);
	for(int i = 1; i <= m; i++){
		int t;  scanf("%lld", &t);
		if(t == 1){
			int x, y, k;
			scanf("%lld%lld%lld", &x, &y, &k);
			insert(1, 1, n, x, y, k);
		}
		else{
			int x, y;
			scanf("%lld%lld", &x, &y);
			printf("%lld\n", calc(1, 1, n, x, y, 0));
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值