暑假训练 2023-7-16 (线段树的有关操作的题目)
补题
题目链接:Transformation
所需算法:线段树
题目大意:让你对一段区间 [l, r]
进行四种操作,分别是在一段区间中都增加c
或者都乘上c
,或者是都变为c
,或者是求出这段区间的每个数的p
次方的和。
对于这些操作,我们只要在线段树中维护 6 个信息
struct Node
{
int l, r; // 节点的区间长度
LL d, mul, add, sum1, sum2, sum3;
// d 表示这段区间是不是有被置为d过,有则为该值d,无则为0
// mul 表示累计乘的值 add 表示累计加的值
// sum1 表示区间的每个元素的值是其值的 1 次方,即 a ^ 1。 sum1 为这些值的总和
// sum2 表示区间的每个元素的值是其值的 2 次方, 即 a ^ 2。 sum2 为这些值的总和
// sum3 依上述类推。
}tr[N * 4];
注意:这里的优先级是 d > mul > add
的,因为整个区间被置为 d
时,那么其 mul
和 add
应分别赋为 1
和 0
。即一旦被赋值为 d
,我们仔细想想会想到 d
就是优先级更高。
而 mul
比 add
优先级更高则是因为在式子 x
时,结果为z
,t
,得pushdown
中,我们按照先将k * x * t
乘给左右子区间,再将B * t
加到左右子区间是合法且易维护的。
另一个需要注意的地方是:
sum3
在区间加上c
的情况可以由公式
sum2
和sum1
依次类推。
sum3
在区间乘上c
的情况可以由公式
sum2
和sum1
依此类推。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <cmath>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };
const int N = 100010, mod = 10007;
int n, m;
int op, x, y, c;
struct Node
{
int l, r;
LL d, mul, add, sum1, sum2, sum3;
}tr[N * 4];
void pushup(int u)
{
tr[u].sum1 = (tr[u * 2].sum1 + tr[u * 2 + 1].sum1) % mod;
tr[u].sum2 = (tr[u * 2].sum2 + tr[u * 2 + 1].sum2) % mod;
tr[u].sum3 = (tr[u * 2].sum3 + tr[u * 2 + 1].sum3) % mod;
}
void pushdown(int u)
{
int l = u * 2, r = u * 2 + 1;
if (tr[u].d)
{
LL d = tr[u].d;
tr[l].sum3 = (LL)(tr[l].r - tr[l].l + 1) * d * d * d % mod;
tr[l].sum2 = (LL)(tr[l].r - tr[l].l + 1) * d * d % mod;
tr[l].sum1 = (LL)(tr[l].r - tr[l].l + 1) * d % mod;
tr[r].sum3 = (LL)(tr[r].r - tr[r].l + 1) * d * d * d % mod;
tr[r].sum2 = (LL)(tr[r].r - tr[r].l + 1) * d * d % mod;
tr[r].sum1 = (LL)(tr[r].r - tr[r].l + 1) * d % mod;
tr[l].mul = 1, tr[l].add = 0, tr[l].d = d, tr[r].mul = 1, tr[r].add = 0, tr[r].d = d;
}
if (tr[u].mul != 1)
{
LL x = tr[u].mul;
tr[l].sum3 = tr[l].sum3 * x * x * x % mod;
tr[l].sum2 = tr[l].sum2 * x * x % mod;
tr[l].sum1 = tr[l].sum1 * x % mod;
tr[r].sum3 = tr[r].sum3 * x * x * x % mod;
tr[r].sum2 = tr[r].sum2 * x * x % mod;
tr[r].sum1 = tr[r].sum1 * x % mod;
tr[l].mul = tr[l].mul * x % mod, tr[l].add = tr[l].add * x % mod;
tr[r].mul = tr[r].mul * x % mod, tr[r].add = tr[r].add * x % mod;
}
if (tr[u].add > 0)
{
LL x = tr[u].add;
tr[l].sum3 = (tr[l].sum3 % mod + 3 * tr[l].sum2 * x % mod + 3 * tr[l].sum1 * x * x % mod + (LL)(tr[l].r - tr[l].l + 1) * x * x * x % mod) % mod;
tr[l].sum2 = (tr[l].sum2 + 2 * tr[l].sum1 * x + (LL)(tr[l].r - tr[l].l + 1) * x * x) % mod;
tr[l].sum1 = (tr[l].sum1 + (LL)(tr[l].r - tr[l].l + 1) * x) % mod;
tr[r].sum3 = (tr[r].sum3 % mod + 3 * tr[r].sum2 * x % mod + 3 * tr[r].sum1 * x * x % mod + (LL)(tr[r].r - tr[r].l + 1) * x * x * x % mod) % mod;
tr[r].sum2 = (tr[r].sum2 + 2 * tr[r].sum1 * x + (LL)(tr[r].r - tr[r].l + 1) * x * x) % mod;
tr[r].sum1 = (tr[r].sum1 + (LL)(tr[r].r - tr[r].l + 1) * x) % mod;
tr[l].add = (tr[l].add + x) % mod, tr[r].add = (tr[r].add + x) % mod;
}
tr[u].mul = 1, tr[u].add = 0, tr[u].d = 0;
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = { l, r, 0, 1, 0, 0, 0, 0 };
}
else
{
int mid = (l + r) >> 1;
tr[u] = { l, r, 0, 1, 0, 0, 0, 0 };
build(u * 2, l, mid), build(u * 2 + 1, mid + 1, r);
}
}
void modify(int u, int l, int r, int c)
{
if (tr[u].l >= l && tr[u].r <= r)
{
if (op == 1)
{
tr[u].sum3 = (tr[u].sum3 % mod + 3 * tr[u].sum2 * c % mod + 3 * tr[u].sum1 * c * c % mod + (LL)(tr[u].r - tr[u].l + 1) * c * c * c % mod) % mod;
tr[u].sum2 = (tr[u].sum2 + 2 * tr[u].sum1 * c + (LL)(tr[u].r - tr[u].l + 1) * c * c) % mod;
tr[u].sum1 = (tr[u].sum1 + (LL)(tr[u].r - tr[u].l + 1) * c % mod) % mod;
tr[u].add = (tr[u].add + c) % mod;
}
else if (op == 2)
{
tr[u].sum3 = tr[u].sum3 * c * c * c % mod;
tr[u].sum2 = tr[u].sum2 * c * c % mod;
tr[u].sum1 = tr[u].sum1 * c % mod;
tr[u].mul = tr[u].mul * c % mod;
tr[u].add = tr[u].add * c % mod;
}
else if (op == 3)
{
tr[u].sum3 = (LL)(tr[u].r - tr[u].l + 1) * c * c * c % mod;
tr[u].sum2 = (LL)(tr[u].r - tr[u].l + 1) * c * c % mod;
tr[u].sum1 = (LL)(tr[u].r - tr[u].l + 1) * c % mod;
tr[u].d = c, tr[u].add = 0, tr[u].mul = 1;
}
}
else
{
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid)modify(u * 2, l, r, c);
if (r > mid)modify(u * 2 + 1, l, r, c);
pushup(u);
}
}
LL query(int u, int l, int r)
{
if (tr[u].l >= l && tr[u].r <= r)
{
if (c == 1)return tr[u].sum1;
else if (c == 2)return tr[u].sum2;
else if (c == 3)return tr[u].sum3;
}
else
{
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
LL sum = 0;
if (l <= mid)sum = query(u * 2, l, r);
if (r > mid)sum = (sum + query(u * 2 + 1, l, r)) % mod;
return sum;
}
}
int main()
{
while (scanf("%d%d", &n, &m), n | m)
{
build(1, 1, n);
while (m--)
{
scanf("%d%d%d%d", &op, &x, &y, &c);
if (op <= 3)modify(1, x, y, c);
else printf("%lld\n", query(1, x, y));
}
}
return 0;
}
转载请注明链接哦!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现