社区讨论
有没有大佬帮帮孩子看看代码吧
P3373【模板】线段树 2参与者 1已保存回复 0
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @ltpp3fc6
- 此快照首次捕获于
- 2024/03/13 19:05 2 年前
- 此快照最后确认于
- 2024/03/13 20:57 2 年前
CPP
#include<iostream>
#define ll long long
#define N 100005
using namespace std;
int n, q, m;
ll a[N]; // 存储原始数组
struct node
{
int l, r, flag, tag, vis; // 区间左右端点、标记变量、标记值、操作类型
ll sum; // 区间和
} tree[N*4]; // 线段树节点
// 构建线段树
void build(int i, int l, int r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].tag = 0; // 区间乘法标记初始化为0
tree[i].flag = 1; // 区间加法标记初始化为1
tree[i].vis = 0; // 节点标记初始化为0
if (l == r)
{
tree[i].sum = a[i]; // 叶节点的值为原始数组的值
return;
}
int m = (l + r) / 2;
build(i * 2, l, m); // 递归构建左子树
build(i * 2 + 1, m + 1, r); // 递归构建右子树
tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; // 更新当前节点的区间和
}
// 下传加法标记
void down1(int i)
{
// 更新左子节点的加法标记和区间和
tree[i * 2].tag = (tree[i * 2].tag + tree[i].tag) % m;
tree[i * 2].sum = (tree[i * 2].sum + (tree[i * 2].r - tree[i * 2].l + 1) * tree[i].tag) % m;
// 更新右子节点的加法标记和区间和
tree[i * 2 + 1].tag = (tree[i * 2 + 1].tag + tree[i].tag) % m;
tree[i * 2 + 1].sum = (tree[i * 2 + 1].sum + (tree[i * 2 + 1].r - tree[i * 2 + 1].l + 1) * tree[i].tag) % m;
tree[i].tag = 0; // 当前节点的加法标记清零
// 更新当前节点的操作类型
if (tree[i].flag > 1)
tree[i].vis = 2;
else
tree[i].vis = 0;
// 更新子节点的操作类型
if (tree[i * 2].vis == 0)
tree[i * 2].vis = 1;
if (tree[i * 2 + 1].vis == 0)
tree[i * 2 + 1].vis = 1;
}
// 下传乘法标记
void down2(int i)
{
// 更新左子节点的乘法标记和区间和
tree[i * 2].flag = (tree[i * 2].flag * tree[i].flag) % m;
tree[i * 2].sum = (tree[i * 2].sum * tree[i].flag) % m;
// 更新右子节点的乘法标记和区间和
tree[i * 2 + 1].flag = (tree[i * 2 + 1].flag * tree[i].flag) % m;
tree[i * 2 + 1].sum = (tree[i * 2 + 1].sum * tree[i].flag) % m;
tree[i].flag = 1; // 当前节点的乘法标记重置为1
// 更新当前节点的操作类型
if (tree[i].tag > 1)
tree[i].vis = 1;
else
tree[i].vis = 0;
// 更新子节点的操作类型
if (tree[i * 2].vis == 0)
tree[i * 2].vis = 2;
if (tree[i * 2 + 1].vis == 0)
tree[i * 2 + 1].vis = 2;
}
// 更新操作1(区间加法)
void update1(int i, int l, int r, int k)
{
if ((tree[i].r < l) || (tree[i].l > r))
return;
if ((tree[i].l >= 1) && (tree[i].r <= r))
{
// 更新当前节点的加法标记和区间和
if (tree[i].vis == 0)
tree[i].vis = 1;
tree[i].tag = (tree[i].tag + k) % m;
tree[i].sum = (tree[i].sum + (tree[i].r - tree[i].l + 1) * k) % m;
return;
}
// 下传标记
if (tree[i].flag > 1 && tree[i].tag > 0)
{
if (tree[i].vis == 1)
{
down1(i);
down2(i);
}
else
{
down2(i);
down1(i);
}
}
else if (tree[i].tag > 0)
down1(i);
else if (tree[i].flag > 1)
down2(i);
// 递归更新左右子节点
update1(i * 2, l, r, k);
update1(i * 2 + 1, l, r, k);
tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % m; // 更新当前节点的区间和
}
// 更新操作2(区间乘法)
void update2(int i, int l, int r, int k)
{
if ((tree[i].r < l) || (tree[i].l > r))
return;
if ((tree[i].l >= 1) && (tree[i].r <= r))
{
// 更新当前节点的乘法标记和区间和
if (tree[i].vis == 0)
tree[i].vis = 2;
tree[i].tag = (tree[i].tag * k) % m;
tree[i].sum = (tree[i].sum * k) % m;
return;
}
// 下传标记
if (tree[i].flag > 1 && tree[i].tag > 0)
{
if (tree[i].vis == 1)
{
down1(i);
down2(i);
}
else
{
down2(i);
down1(i);
}
}
else if (tree[i].tag > 0)
down1(i);
else if (tree[i].flag > 1)
down2(i);
// 递归更新左右子节点
update2(i * 2, l, r, k);
update2(i * 2 + 1, l, r, k);
tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % m; // 更新当前节点的区间和
}
// 查询操作
ll query(int i, int l, int r)
{
if ((tree[i].r < l) || (tree[i].l > r))
return 0;
if ((tree[i].l >= 1) && (tree[i].r <= r))
return tree[i].sum;
// 下传标记
if (tree[i].flag > 1 && tree[i].tag > 0)
{
if (tree[i].vis == 1)
{
down1(i);
down2(i);
}
else
{
down2(i);
down1(i);
}
}
else if (tree[i].tag > 0)
down1(i);
else if (tree[i].flag > 1)
down2(i);
return (query(i * 2, l, r) + query(i * 2 + 1, l, r)) % m; // 递归查询左右子节点并返回结果
}
int main()
{
cin >> n >> q >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n); // 构建线段树
for (int i = 1; i <= q; i++)
{
int v;
int x, y, k;
cin >> v;
if (v == 1)
{
cin >> x >> y >> k;
update2(1, x, y, k); // 区间乘法更新操作
}
else if (v == 2)
{
cin >> x >> y >> k;
update1(1, x, y, k); // 区间加法更新操作
}
else
{
cin >> x >> y;
ll ans = query(1, x, y); // 查询操作
cout << ans << endl;
}
}
return 0;
}
回复
共 0 条回复,欢迎继续交流。
正在加载回复...