题解
题目大意 给你一个长度为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;
}