【模板】线段树2

题意简述

已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和

代码

#include <cstdio>
using namespace std;
typedef long long ll;
ll n, m, opt, x, y, k, mod;
ll a[400010], la1[400010], la2[400010];
void push_up(ll x)
{
	a[x] = (a[x << 1] + a[x << 1 | 1]) % mod;
}
void push_down(ll x, ll len)
{
	if (la2[x] != 1)
	{
		(a[x << 1] *= la2[x]) %= mod;
		(a[x << 1 | 1] *= la2[x]) %= mod;
		(la1[x << 1] *= la2[x]) %= mod;
		(la1[x << 1 | 1] *= la2[x]) %= mod;
		(la2[x << 1] *= la2[x]) %= mod;
		(la2[x << 1 | 1] *= la2[x]) %= mod;
		la2[x] = 1;
	}
	if (la1[x])
	{
		(a[x << 1] += la1[x] * (len - (len >> 1)) % mod) %= mod;
		(a[x << 1 | 1] += la1[x] * (len >> 1) % mod) %= mod;
		(la1[x << 1] += la1[x]) %= mod;
		(la1[x << 1 | 1] += la1[x]) %= mod;
		la1[x] = 0;
	}
}
void build(ll x, ll l, ll r)
{
	la2[x] = 1;
	if (l == r)
	{
		scanf("%lld", &a[x]);
		return;
	}
	ll mid = l + r >> 1;
	build(x << 1, l, mid);
	build(x << 1 | 1, mid + 1, r);
	push_up(x);
}
void multiply(ll x, ll l, ll r, ll l1, ll r1)
{
	if(l1 <= l && r <= r1)
	{
		(a[x] *= k) %= mod;
		(la1[x] *= k) %= mod;
		(la2[x] *= k) %= mod;
		return;
	}
	push_down(x, r - l + 1);
	ll mid = l + r >> 1;
	if (l1 <= mid) multiply(x << 1, l, mid, l1, r1);
	if (r1 >  mid) multiply(x << 1 | 1, mid + 1, r, l1, r1);
	push_up(x);
}
void add(ll x, ll l, ll r, ll l1, ll r1)
{
	if (l1 <= l && r <= r1)
	{
		(a[x] += (r - l + 1) * k % mod) %= mod;
		(la1[x] += k) %= mod;
		return;
	}
	push_down(x, r - l + 1);
	ll mid = l + r >> 1;
	if (l1 <= mid) add(x << 1, l, mid, l1, r1);
	if (r1 >  mid) add(x << 1 | 1, mid + 1, r, l1, r1);
	push_up(x);
}
ll query(ll x, ll l, ll r, ll l1, ll r1, ll ans = 0)
{
	if (l1 <= l && r <= r1)	return a[x];
	push_down(x, r - l + 1);
	ll mid = l + r >> 1;
	if (l1 <= mid) (ans += query(x << 1, l, mid, l1, r1)) %= mod;
	if (r1 >  mid) (ans += query(x << 1 | 1, mid + 1, r, l1, r1)) %= mod;
	return ans;
}
int main()
{
	scanf("%lld%lld%lld", &n, &m, &mod);
	build(1, 1, n);
	for (register ll i = 1; i <= m; ++i)
	{
		scanf("%lld", &opt);
		if (opt == 1)
		{
			scanf("%lld%lld%lld", &x, &y, &k);
			multiply(1, 1, n, x, y);
		}
		if (opt == 2)
		{
			scanf("%lld%lld%lld", &x, &y, &k);
			add(1, 1, n, x, y);
		}
		if (opt == 3)
		{
			scanf("%lld%lld", &x, &y);
			printf("%lld\n", query(1, 1, n, x, y));
		}
	}
}
posted @ 2018-08-13 20:06  xuyixuan  阅读(124)  评论(0编辑  收藏  举报