Transformation HDU - 4578 线段树

题解

题目大意 给你一个长度为n的区间 有三种操作
1将区间[l, r]加上c 2将区间[l, r]乘上c 3将区间[l, r]改为c
4为询问 询问区间[l, r]的每个元素的p次方 p只为1、2、3

线段树维护区间元素的1、2、3次方和 lazy三种操作
通过公式(A+c) ^ 2 = A ^ 2 + 2Ac + c ^ 2 和 (A+c) ^ 3 = A ^ 3 + 3A ^ 2c + 3 Ac ^ 2 + c^3维护
lazy标时 如果有set就先将之前的add和mul清零再覆盖
计算s1 s2 s3时需要先乘后加

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MOD = 1e4 + 7;
const int MAXN = 1e5 + 10;

struct node
{
	int l, r;
	ll s1, s2, s3; //次方和
	ll add, mul, set; //lazy
	void Modify(ll a, ll m, ll s) //修改节点值
	{
		int n = r - l + 1; //区间长度
		if (s) //有set先执行
		{
			s1 = s * n % MOD;
			s2 = s * s % MOD * n % MOD;
			s3 = s * s % MOD * s % MOD * n % MOD;
		}
		s3 = s3 * m % MOD * m % MOD * m % MOD; //先分别乘再分别加 更新顺序321
		s2 = s2 * m % MOD * m % MOD;
		s1 = s1 * m % MOD;
		s3 = (s3 + s2 * a % MOD * 3 % MOD + s1 * a % MOD * a % MOD * 3 % MOD + a * a % MOD * a % MOD * n % MOD) % MOD;
		s2 = (s2 + s1 * a % MOD * 2 % MOD + a * a % MOD * n % MOD) % MOD;
		s1 = (s1 +a * n % MOD) % MOD;
	}
	void Lazy(ll a, ll m, ll s)
	{
		if (s) //set直接将add和mul清除
			add = 0, mul = 1,set = s;
		add = (add * m % MOD + a) % MOD, mul = mul * m % MOD; //add乘mul再加a mul直接乘m
	}
}tre[MAXN * 4];
inline void PushUp(int x)
{
	tre[x].s1 = (tre[x << 1].s1 + tre[x << 1 | 1].s1) % MOD;
	tre[x].s2 = (tre[x << 1].s2 + tre[x << 1 | 1].s2) % MOD;
	tre[x].s3 = (tre[x << 1].s3 + tre[x << 1 | 1].s3) % MOD;
}
inline void PushDown(int x)
{
	if (tre[x].add || tre[x].mul != 1 || tre[x].set)
	{
		tre[x << 1].Modify(tre[x].add, tre[x].mul, tre[x].set);
		tre[x << 1 | 1].Modify(tre[x].add, tre[x].mul, tre[x].set);
		tre[x << 1].Lazy(tre[x].add, tre[x].mul, tre[x].set);
		tre[x << 1 | 1].Lazy(tre[x].add, tre[x].mul, tre[x].set);
		tre[x].add = tre[x].set = 0;
		tre[x].mul = 1;
	}
}
void Build(int x, int l, int r)
{
	tre[x].l = l, tre[x].r = r, tre[x].s1 = tre[x].s2 = tre[x].s3 = tre[x].add = tre[x].set = 0, tre[x].mul = 1;
	if (l == r)
		return;
	else
	{
		int m = l + r >> 1;
		Build(x << 1, l, m);
		Build(x << 1 | 1, m + 1, r);
	}
}
void Update(int x, int pl, int pr, ll a, ll m, ll s)
{
	int l = tre[x].l, r = tre[x].r;
	if (pl <= l && r <= pr)
	{
		tre[x].Lazy(a, m, s);
		tre[x].Modify(a, m, s); //不能用lazy修改
	}
	else
	{
		PushDown(x);
		int mid = l + r >> 1; //m重名
		if (mid >= pl)
			Update(x << 1, pl, pr, a, m, s);
		if (mid < pr)
			Update(x << 1 | 1, pl, pr, a, m, s);
		PushUp(x);
	}
}
ll Query(int x, int pl, int pr, int p) //p次方
{
	int l = tre[x].l, r = tre[x].r;
	if (pl <= l && r <= pr)
	{
		if (p == 1)
			return tre[x].s1;
		if (p == 2)
			return tre[x].s2;
		return tre[x].s3;
	}
	else
	{
		PushDown(x);
		int m = l + r >> 1;
		ll res = 0;
		if (m >= pl)
			res = (res + Query(x << 1, pl, pr, p)) % MOD;
		if (m < pr)
			res = (res + Query(x << 1 | 1, pl, pr, p)) % MOD;
		PushUp(x);
		return res;
	}
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int N, M;
	while (cin >> N >> M, N && M)
	{
		Build(1, 1, N);
		int op, x, y, c;
		for (int i = 0; i < M; i++)
		{
			scanf("%d%d%d%d", &op, &x, &y, &c);
			if (op == 1)
				Update(1, x, y, c, 1, 0);
			else if (op == 2)
				Update(1, x, y, 0, c, 0);
			else if (op == 3)
				Update(1, x, y, 0, 1, c);
			else if (op == 4)
				printf("%lld\n", Query(1, x, y, c));
		}
	}

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值