线段树-多个懒标记pushdown
这里需要用到两个懒标记,一个懒标记为add,记录加,另一个懒标记为mul,记录乘。
我们需要规定一个优先级,然后考虑如何将懒标记下传。
这里无非有两种顺序,一种是先乘后加,另一种是先加后乘。
我们先看先加后乘。
\]
当我们的懒标记$ add2 、 mul2 $下传
\]
\]
我们更新懒标记仍需要化成
\]
对于(1)
\]
可以看出如果要下传add标记就需要add2必须满足mul1,这个显然不容易满足
对于(2)
\]
我们之间将mul标记更新为$ mul1 * mul2 $ 即可
显然先加后乘,下传加号标记是不好处理的
我们再看先乘后加
\]
当懒标记$ add2 或 mul2 $下传
\]
\]
对于(1)
我们只需要将add标记更新为$ add1 + add2$即可
对于(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;
}
这道题目也需要两个懒标记,一个把一个区间的所有数变成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的更多相关文章
- 【HDU 4614】Vases and Flowers(线段树区间更新懒惰标记)
题目0到n-1的花瓶,操作1在下标a开始插b朵花,输出始末下标.操作2清空[a,b]的花瓶,求清除的花的数量.线段树懒惰标记来更新区间.操作1,先查询0到a-1有num个空瓶子,然后用线段树的性质,或 ...
- [HDOJ4578]Transformation(线段树,多延迟标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...
- 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化
4636: 蒟蒻的数列 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 247 Solved: 113[Submit][Status][Discuss ...
- 扶桑号战列舰 (单调栈+线段树区间更新懒惰标记 or 栈)
传送门 •题目描述 题目描述 众所周知,一战过后,在世界列强建造超无畏级战列舰的竞争之中,旧日本海军根据“个舰优越主义”,建造了扶桑级战列舰,完工时为当时世界上武装最为强大的舰只. 同时,扶桑号战列舰 ...
- 扫描线总结【线段树特殊性质,没有pushdown、query操作】
扫描线 题意 多个矩阵求交集,线段树的特殊操作,非常特殊的情况,一堆证明之后,就没有pushdown操作. 没有pushdown操作,也没有query操作,直接tr[1].len. 亚特兰蒂斯 由于点 ...
- 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之间 ...
- 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)
欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memor ...
- FZU-1608 Huge Mission 线段树(更新懒惰标记)
题目链接: https://cn.vjudge.net/problem/FZU-1608 题目大意: 长度n,m次操作:每次操作都有三个数:a,b,c:意味着(a,b]区间单位长度的价值为c,若某段长 ...
- HDU 4553 约会安排(线段树区间合并+双重标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...
- hdu1698 Just a Hook (线段树区间更新 懒惰标记)
Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
随机推荐
- 虚幻引擎 4 学习笔记 [1] :蓝图编程 Demo
虚幻引擎 4 学习笔记 [1] :蓝图编程 Demo 最近学习虚幻引擎,主要看的是 Siki 学院的课,课程链接:Unreal蓝图案例 - 基础入门 - SiKi学院|SiKi学堂 - unity ...
- CentOS使用iptables开放3000端口
关闭firewall systemctl stop firewalld.service 禁止firewall开机启动 systemctl disable firewalld.service 设置ipt ...
- SpringBoot实现动态数据源配置
场景描述: 前一阵子接手的新项目中需要使用2个数据源. 一个叫行云数据库,一个叫OceanBase数据库. 就是说,我有时候查询要查行云的数据,有时候查询要查 OceanBase 的数据,咋办? 废话 ...
- Midjourney|文心一格prompt教程[技巧篇]:生成多样性、增加艺术风格、图片二次修改、渐进优化、权重、灯光设置等17个技巧等你来学
Midjourney|文心一格prompt教程[技巧篇]:生成多样性.增加艺术风格.图片二次修改.渐进优化.权重.灯光设置等17个技巧等你来学 1.技巧一:临摹 我认为学习图片类的 prompt,跟学 ...
- 全流程机器视觉工程开发(三)任务前瞻 - 从opencv的安装编译说起,到图像增强和分割
前言 最近开始做这个裂缝识别的任务了,大大小小的问题我已经摸得差不多了,然后关于识别任务和分割任务我现在也弄的差不多了. 现在开始做正式的业务,也就是我们说的裂缝识别的任务.作为前言,先来说说场景: ...
- playwright 一些方法解决cloudflare防护页的问题
在尝试从一个使用Cloudflare Web应用程序防火墙(WAF)保护的网站获取数据时,我遇到了一些挑战.该网站的安全措施非常严格,以至于在正常浏览几个页面后,Cloudflare的检查页面就会出现 ...
- 【算法】priority_queue在力扣题中的应用 | 力扣692 | 力扣347 | 力扣295 【超详细的注释和算法解释】
说在前面的话 博主也好长一段时间没有更新力扣的刷题系列了,今天给大家带来一些优先队列的经典题目,今天博主还是用C++给大家讲解,希望大家可以从中学到一些东西. 前言 那么这里博主先安利一下一些干货满满 ...
- curl接口调用
CURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP.FTP.TELNET等.最爽的是,PHP也支持 CURL 库.使用PHP的CURL 库可以简单和有效地去抓网页.你只 ...
- 【题解】T378828 位运算
位运算 题目背景 题目由 daiyulong20120222 创作(me) 并由 QBW1117完善以及数据 . 题目描述 给定两个数\(x,y\) ,在给定一个位运算符号 \(c\). 请你列出 \ ...
- .NET Core 在 K8S 上的开发实践--学习笔记
摘要 本主题受众是架构师,开发人员,互联网企业 IT 运维人员.大纲:1. K8S 对应用的要求:2. .NET Core 上 K8S 的优势:3. K8S 下的 .NET Core 配置:4. .N ...