luogu P3372ybtoj线段树课堂过关例题2区间查改 &模板线段树 1

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3372ybtoj线段树课堂过关例题2区间查改 &模板线段树 1相关的知识,希望对你有一定的参考价值。

【例题2】区间查改 & 【模板】线段树 1


Link

luogu P3372 【模板】线段树 1
ybtoj【线段树课堂过关】【例题2】区间查改
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了


题目大意

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

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

解题思路

模板带lazy标的线段树
对于每个需要修改的区间(例[1-2] + 5),并不寻找区间中单个单个的点([1-1] + 5,[2-2] + 5)
而是直接在区间上修改([1,2].s + 5 * 2),并且打上lazy标([1,2].lazy + 5)
等需要找区间中更小的区间时再把lazy标下传([1,1].s + 5,[1,1].lazy + 5;[2,2].s + 5,[2,2].lazy + 5)


Code

#include <iostream>
#include <cstdio>
#define ll long long

using namespace std;

struct DT{
	ll s, lazy;
}tree[8001000];
int n, m, c, x, y;
int s, a[1001000];

void down(int root, int l, int r) {  //下传lazy标
	int mid = (l + r) / 2;
	tree[root * 2].s += tree[root].lazy * (mid - l + 1);
	tree[root * 2].lazy += tree[root].lazy;
	
	tree[root * 2 + 1].s += tree[root].lazy * (r - (mid + 1) + 1);
	tree[root * 2 + 1].lazy += tree[root].lazy;
	
	tree[root].lazy = 0;
}

void build(int root, int l, int r) {
	if(l == r) {
		tree[root].s = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(root * 2, l, mid);
	build(root * 2 + 1, mid + 1, r);
	tree[root].s = tree[root * 2].s + tree[root * 2 + 1].s;
}

void add(int root, int l, int r, int x, int y, int s) {
	if (l >= x && r <= y) {
		tree[root].s += 1ll * s * (r - l + 1);
		tree[root].lazy += s;
		return;
	}
	down(root, l, r);  //需要寻找更小的区间=>下传
	int mid = (l + r) / 2;
	if(x <= mid)
		add(root * 2, l, mid, x, y, s);
	if(y > mid) 
		add(root * 2 + 1, mid + 1, r, x, y, s);
	tree[root].s = tree[root * 2].s + tree[root * 2 + 1].s;
}

ll find(int root, int l, int r, int x, int y) {
	if (l >= x && r <= y) return tree[root].s;
	down(root, l, r);
	int mid = (l + r) / 2;
	ll ans = 0;
	if(x <= mid)
		ans += find(root * 2, l, mid, x, y);
	if(y > mid)
		ans += find(root * 2 + 1, mid + 1, r, x, y);
	return ans;
}

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	build(1, 1, n);
	for(int i = 1; i <= m; i++) {
		scanf("%d %d %d", &c, &x, &y);
		if(c == 1) {
			scanf("%d", &s);
			add(1, 1, n, x, y, s);
		} else
			printf("%lld\\n", find(1, 1, n, x, y));
	}
}

以上是关于luogu P3372ybtoj线段树课堂过关例题2区间查改 &模板线段树 1的主要内容,如果未能解决你的问题,请参考以下文章

ybtoj线段树课堂过关例题1求区间和

ybtoj 单调队列课堂过关luogu P1886例题1滑动窗口

luogu UVA10559 ybtoj 区间DP课堂过关 例题3消除木块 & 方块消除 Blocks

luogu P4170ybtoj 区间DP课堂过关 例题2木板涂色 & [CQOI2007]涂色

luogu P1352ybtoj 树形DP课堂过关 例题1树上求和 & 没有上司的舞会

luogu P1880ybtoj 区间DP课堂过关 例题1石子合并 & [NOI1995] 石子合并