线段树2 RE求助
查看原帖
线段树2 RE求助
167697
BartAllen楼主2023/1/4 14:11
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e5 + 5;

struct SegmentTree{
	int l, r;	// 子树编号
	ll sum, add, mu;	// 节点信息
	#define _l(x) tree[x].l
	#define _r(x) tree[x].r
	#define _sum(x) tree[x].sum
	#define _add(x) tree[x].add	// lazy tag加法延迟标记
	#define _mu(x) tree[x].mu	// lazy tag乘法延迟标记
} tree[N * 4];	// 结构体存储线段树

int a[N], n, m, Mod;

void build(int p, int l, int r) {	// 建树
	_l(p) = l, _r(p) = r;	// 节点p代表区间[l,r] 
	if (l == r) {	//叶节点
		_sum(p) = a[l];
		return;
	}
	int mid = (l + r) / 2;	// 折半
	build(p * 2, l, mid);	// 左子节点[l,mid],编号p*2 
	build(p * 2 + 1, mid + 1, r);	// 右子节点[mid+1,r],编号p*2+1 
	_sum(p) = (_sum(p * 2) + _sum(p * 2 + 1)) % Mod;	// 从上往下传递信息
}

void spread(int p) {	// 打lazy tag
	if (_add(p)) {	// 节点p有标记
		// 修改子节点信息
		_sum(p * 2) = (ll)(_mu(p) * _sum(p * 2) + ((_r(p * 2) - _l(p * 2) + 1) * _add(p)) % Mod) % Mod;
		_sum(p * 2 + 1) = (ll)(_mu(p) * _sum(p * 2 + 1) + ((_r(p * 2 + 1) - _l(p * 2 + 1) + 1) * _add(p)) % Mod) % Mod;
		// 打上两运算的lazy tag
		_mu(p * 2) = (ll)(_mu(p * 2) * _mu(p)) % Mod;
		_mu(p * 2 + 1) = (ll)(_mu(p * 2 + 1) * _mu(p)) % Mod;
		_add(p * 2) = (ll)(_add(p * 2) * _mu(p) + _add(p)) % Mod;
		_add(p * 2 + 1) = (ll)(_add(p * 2 + 1) * _mu(p) + _add(p)) % Mod;
	}
}

void change_add(int p, int l, int r, int d) {	// 区间加法
	if (l <= _l(p) && r >= _r(p)) {	// 完全覆盖
		_sum(p) += (ll)d * (_r(p) - _l(p) + 1);	// 更新节点信息
		_add(p) += d;	// 给节点打lazy tag
		_sum(p) %= Mod, _add(p) %= Mod;
		return;
	}	// 找到叶节点
	spread(p);	// 下传lazy tag
	int mid = (_l(p) + _r(p)) / 2;
	if (l <= mid) change_add(p * 2, l, r, d);	// x属于左半区间
	if (r > mid) change_add(p * 2 + 1, l, r, d);	// x属于右半区间
	_sum(p) = (_sum(p * 2) + _sum(p * 2 + 1)) % Mod;	// 从上往下更新信息
}

void change_mu(int p, int l, int r, int d) {	// 区间乘法 
	if (_l(p) >= l && _r(p) <= r) {	// 完全覆盖
		_add(p) = (_add(p) * d) % Mod;	// 先乘后加,后面的加数不用乘d 
		_mu(p) = (_mu(p) * d) % Mod;
		_sum(p) = (_mu(p) * d) % Mod;
		return;
	}
	spread(p);	// 下传lazy tag
	ll mid = (_r(p) + _l(p)) / 2;
	if (l <= mid) change_mu(p * 2, l, r, d);
	if (r > mid) change_mu(p * 2 + 1, l, r, d);
	_sum(p) = (_sum(p * 2) + _sum(p * 2 + 1)) % Mod;	// 从上往下更新信息
}

ll ask(int p, int l, int r) {
	if (l <= _l(p) && r >= _r(p)) return _sum(p);	// 完全包含
	spread(p);	//下传lazy tag
	int mid = (_l(p) + _r(p)) / 2;
	ll val = 0;
	if (l <= mid) val += ask(p * 2, l, r);	// 左子节点有重叠
	if (r > mid) val += ask(p * 2 + 1, l, r);	// 右子节点有重叠
	val %= Mod;
	return val;
}

int main() {
	scanf("%d%d", &n, &m, &Mod);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	build(1, 1, n);
	while (m--) {
		int op, l, r, d;
		scanf("%d%d%d", &op, &l, &r);
		if (op == 1) {
			scanf("%d", &d);
			change_mu(1, l, r, d);
		}
		if (op == 2) {
			scanf("%d", &d);
			change_add(1, l, r, d);
		}
		else printf("%lld\n", ask(1, l, r));
	}
	return 0;
}
2023/1/4 14:11
加载中...