P3373 【模板】线段树 2

这里需要用到两个懒标记,一个懒标记为add,记录加,另一个懒标记为mul,记录乘。

我们需要规定一个优先级,然后考虑如何将懒标记下传。

这里无非有两种顺序,一种是先乘后加,另一种是先加后乘。

我们先看先加后乘

\[(sum + add1) * mul1
\]

当我们的懒标记$ add2 、 mul2 $下传

\[(sum + add1) * mul1 + add2 \quad (1)
\]
\[(sum + add1) * mul1 * mul2 \quad (2)
\]

我们更新懒标记仍需要化成

\[(sum + add) * mul
\]

对于(1)

\[(sum + add1 + \frac{add2} {mul1}) * mul1 \quad (1)
\]

可以看出如果要下传add标记就需要add2必须满足mul1,这个显然不容易满足

对于(2)

\[(sum + add1) * mul1 * mul2 \quad (2)
\]

我们之间将mul标记更新为$ mul1 * mul2 $ 即可

显然先加后乘,下传加号标记是不好处理的

我们再看先乘后加

\[sum * mul1 + add1
\]

当懒标记$ add2 或 mul2 $下传

\[sum * mul1 + add1 + add2 \quad (1)
\]
\[(sum * mul1 + add1) * mul2 \quad (2)
\]

对于(1)

我们只需要将add标记更新为$ add1 + add2$即可

对于(2)

\[sum * mul1 * mul2 + add1 * mul2 \quad (2)
\]

我们需要将add标记跟新为$ add1 * mul2 , 将mul标记更新为 mul1 * mul2$

我们发现先乘后加的情况,懒标记的下传都很容易做到,所以我们选择先乘后加这种顺序。

下面是代码:


#include <bits/stdc++.h>
#define LL long long
#define ls p<<1
#define rs p<<1|1
#define endl '\n'
#define PII pair<int, int>
using namespace std;
using ll = long long;
const int N = 1e6 + 10;
ll n, q, mod, a[N];
struct node
{
ll l, r, sum, mul, add;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define mul(x) tree[x].mul
#define add(x) tree[x].add
#define sum(x) tree[x].sum
} tree[4 * N]; void pushup(int p)
{
sum(p) = (sum(ls) + sum(rs)) % mod;
} void build(int p, ll l, ll r)
{
l(p) = l; r(p) = r; mul(p) = 1, add(p) = 0;
if(l == r)
{
sum(p) = a[l] % mod;
return;
}
int mid = (l(p) + r(p)) >> 1;
build(ls, l(p), mid), build(rs, mid + 1, r(p));
pushup(p);
} void pushdown(int p)
{
sum(ls) = (sum(ls) * mul(p) + (r(ls) - l(ls) + 1) * add(p)) % mod;
sum(rs) = (sum(rs) * mul(p) + (r(rs) - l(rs) + 1) * add(p)) % mod; mul(ls) = (mul(ls) * mul(p)) % mod;
mul(rs) = (mul(rs) * mul(p)) % mod; add(ls) = (add(ls) * mul(p) + add(p)) % mod;
add(rs) = (add(rs) * mul(p) + add(p)) % mod; add(p) = 0; mul(p) = 1;
} void modify(int p, ll l, ll r, int op, ll x)
{
if(l(p) >= l && r(p) <= r)
{
if(op == 1)
{
sum(p) = (sum(p) * x) % mod;
mul(p) = (mul(p) * x) % mod;
add(p) = (add(p) * x) % mod;
}
else if(op == 2)
{
sum(p) = (sum(p) + (r(p) - l(p) + 1) * x) % mod;
add(p) = (add(p) + x) % mod;
}
return;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
if(l <= mid) modify(ls, l, r, op, x);
if(r > mid) modify(rs , l, r, op, x);
pushup(p);
} ll query(int p, ll l, ll r)
{
if(l(p) >= l && r(p) <= r) return sum(p);
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
ll val = 0;
if(l <= mid) val = (val + query(ls, l, r)) % mod;
if(r > mid) val = (val + query(rs, l, r)) % mod;
return val;
} void solve()
{
cin >> n >> mod;
for(int i = 1; i <= n; ++ i) cin >> a[i];
cin >> q;
build(1, 1, n);
for(int i = 1; i <= q; ++ i)
{
int op; cin >> op;
if(op == 1)
{
ll l, r, x; cin >> l >> r >> x;
modify(1, l, r, op, x);
}
else if(op == 2)
{
ll l, r, x; cin >> l >> r >> x;
modify(1, l, r, op, x);
}
else
{
int l, r; cin >> l >> r;
cout << query(1, l, r) << endl;
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
// freopen("1.in", "r", stdin);
solve();
return 0;
}

P1253 扶苏的问题

这道题目也需要两个懒标记,一个把一个区间的所有数变成x的懒标记记为add1,另一个懒标记记为add2

特殊性:操作一会覆盖,假设有操作1,新增懒标记为$ add1 时, 我们就将 add2清空$

当新增一个操作2时,我们就直接增加 $ add2 标记即可 $

#include <bits/stdc++.h>
#define LL long long
#define ls p<<1
#define rs p<<1|1
#define PII pair<int, int>
using namespace std;
using ll = long long;
const int N = 1e6 + 10;
int n, q, a[N];
struct node
{
int l, r, st;
ll mx, add1, add2;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define add1(x) tree[x].add1
#define add2(x) tree[x].add2
#define st(x) tree[x].st
#define mx(x) tree[x].mx
} tree[4 * N]; void pushup(int p)
{
mx(p) = max(mx(ls), mx(rs));
} void build(int p, int l, int r)
{
l(p) = l; r(p) = r; st(p) = 0;
if(l == r)
{
mx(p) = a[l];
return;
}
int mid = (l(p) + r(p)) >> 1;
build(ls, l(p), mid), build(rs, mid + 1, r(p));
pushup(p);
} void pushdown(int p)
{
if(st(p))
{
st(ls) = st(rs) = 1;
add1(ls) = add1(rs) = add1(p);
add2(ls) = add2(rs) = 0;
mx(ls) = mx(rs) = add1(p);
st(p) = add1(p) = 0;
}
mx(ls) += add2(p); mx(rs) += add2(p);
add2(ls) += add2(p); add2(rs) += add2(p);
add2(p) = 0;
} void modify(int p, int l, int r, int op, int x)
{
if(l(p) >= l && r(p) <= r)
{
if(op == 1)
{
mx(p) = x;
st(p) = 1;
add1(p) = x;
add2(p) = 0;
}
else
{
mx(p) += x;
add2(p) += x;
}
return;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
if(l <= mid) modify(ls, l, r, op, x);
if(r > mid) modify(rs , l, r, op, x);
pushup(p);
} ll query(int p, int l, int r)
{
if(l(p) >= l && r(p) <= r) return mx(p);
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
ll val = -1e18;
if(l <= mid) val = max(val, query(ls, l, r));
if(r > mid) val = max(val, query(rs, l, r));
// pushup(p);
return val;
} void solve()
{
cin >> n >> q;
for(int i = 1; i <= n; ++ i) cin >> a[i];
build(1, 1, n);
for(int i = 1; i <= q; ++ i)
{
int op; cin >> op;
if(op == 1)
{
int l, r, x; cin >> l >> r >> x;
modify(1, l, r, op, x);
}
else if(op == 2)
{
int l, r, x; cin >> l >> r >> x;
modify(1, l, r, op, x);
}
else
{
int l, r; cin >> l >> r;
cout << query(1, l, r) << endl;
}
} }
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
// freopen("1.in", "r", stdin);
solve();
return 0;
}

线段树-多个懒标记pushdown的更多相关文章

  1. 【HDU 4614】Vases and Flowers(线段树区间更新懒惰标记)

    题目0到n-1的花瓶,操作1在下标a开始插b朵花,输出始末下标.操作2清空[a,b]的花瓶,求清除的花的数量.线段树懒惰标记来更新区间.操作1,先查询0到a-1有num个空瓶子,然后用线段树的性质,或 ...

  2. [HDOJ4578]Transformation(线段树,多延迟标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...

  3. 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

    4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss ...

  4. 扶桑号战列舰 (单调栈+线段树区间更新懒惰标记 or 栈)

    传送门 •题目描述 题目描述 众所周知,一战过后,在世界列强建造超无畏级战列舰的竞争之中,旧日本海军根据“个舰优越主义”,建造了扶桑级战列舰,完工时为当时世界上武装最为强大的舰只. 同时,扶桑号战列舰 ...

  5. 扫描线总结【线段树特殊性质,没有pushdown、query操作】

    扫描线 题意 多个矩阵求交集,线段树的特殊操作,非常特殊的情况,一堆证明之后,就没有pushdown操作. 没有pushdown操作,也没有query操作,直接tr[1].len. 亚特兰蒂斯 由于点 ...

  6. HDU 3911 Black And White (线段树区间合并 + lazy标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3911 给你n个数0和1,m个操作: 0操作  输出l到r之间最长的连续1的个数 1操作  将l到r之间 ...

  7. 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)

    欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memor ...

  8. FZU-1608 Huge Mission 线段树(更新懒惰标记)

    题目链接: https://cn.vjudge.net/problem/FZU-1608 题目大意: 长度n,m次操作:每次操作都有三个数:a,b,c:意味着(a,b]区间单位长度的价值为c,若某段长 ...

  9. HDU 4553 约会安排(线段树区间合并+双重标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...

  10. hdu1698 Just a Hook (线段树区间更新 懒惰标记)

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

随机推荐

  1. 跟着文档学Fabric:获取通道配置

    原文在这里. 1. 获取通道配置 peer channel fetch config config_block.pb -o $ORDERER_CONTAINER -c $CH_NAME --tls - ...

  2. 紫 distance

    仅此纪念我爆掉的T3 紫,即RE,运行出错,梦幻,而又不失杀气 根据<雪distance>改编,分为提交前,评测前,评测时,评测后 你说我考试AK,可我却运行出错 任凭无尽的懊悔将我淹没, ...

  3. Netty-核心模块组件-4

    Netty 核心模块组件 一.Bootstrap.ServerBootstrap 1.Bootstrap 意思是引导,一个 Netty 应用通常由一个 Bootstrap 开始,主要作用是配置整个 N ...

  4. SSM整合思维(随手记)

    整合方向(整合思路): 用Spring去整合SpringMVC和Mybatis. 一.先创建Spring项目测试运行成功后,再创建SpringMVC项目再单独测试SpringMVC项目如果运行成功后即 ...

  5. 认识3D模型-GLTF文件

    GLTF文件格式 glTF的全称(Graphics Language Transmission Format)图形语言传输格式.是三维场景和模型的标准文件格式. glTF 核心是 JSON 文件,描述 ...

  6. 【树】N叉树的遍历【力扣589、力扣590】超详细的解释和注释

    说在前面 欢迎朋友们来到我的博客. 今天我们的重点是,N叉树的遍历. 今天,博主就带来两道经典的题目,领着大家理解N叉树的前序遍历和后序遍历! 当然,还想学习其它算法的朋友们,可以通过订阅博主的算法专 ...

  7. Leetcode刷题第五天-二分法-回溯

    215:第k个最大元素 链接:215. 数组中的第K个最大元素 - 力扣(LeetCode) em~~怎么说呢,快速选择,随机定一个目标值,开始找,左边比目标小,右边比目标大,左右同时不满足时,交换左 ...

  8. 程序员必备技能:一键创建windows 服务

    使用windows开发或者使用windows服务器的朋,应该经常会遇到有些程序要开机启动,或者有些服务要持续执行. 这样最稳定可靠的,就是把程序创建为windows服务. 以下bat脚本,仅供参考. ...

  9. 问题:Duplicate报错RMAN-03009, ORA-17628, ORA-19505

    前面文章提到,这周末帮一个客户测试报错场景: 客户通过duplicate生产备库的方式创建cascade备库. 发现每次都会遇到两个文件报错,ORA-17628: Oracle error 19505 ...

  10. OGG-01496 Failed to open target trail file ./dirdat/ra000002, at RBA 2179

    1.问题描述 在启动OGG源端的投递进程时,报错:OGG-01496 OGG-01496 Failed to open target trail file ./dirdat/ra000002, at ...