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

本文介绍了一种使用线段树和懒惰传播技术来高效处理区间操作和查询的问题解决策略。具体包括了加法、乘法、赋值及求区间内元素的幂次运算。通过递归分解和延迟更新机制,实现了对复杂操作的快速响应。
1222

被折叠的 条评论
为什么被折叠?



