洛谷题单指南-线段树-P3373 【模板】线段树 2

news/2024/11/29 17:15:49/文章来源:https://www.cnblogs.com/jcwy/p/18574689

原题链接:https://www.luogu.com.cn/problem/P3373

题意解读:对于序列a[n],支持三种操作:1.对区间每个数乘上一个数 2.对区间每个数加上一个数 3.求区间和

解题思路:由于支持乘、加两种区间修改操作,是线段树的另一种典型应用:多个懒标记

显然,这里需要两个懒标记,mul表示对子节点区间每个数乘mul,add表示对子节点区间每个数加上add,节点定义如下:

struct Node 
{int l, r;LL sum; //区间和LL mul; //懒标记,子节点区间每个数乘上mul,默认值为1LL add; //懒标记,子节点区间每个数加上add,默认值为0
} tr[N * 4];

下面就要考虑sum、mul、add如何修改的问题

对于一个节点u,

如果要对其区间每个数乘mul,则有tr[u].sum = tr[u].sum * mul

如果要对其区间每个数加add,则有tr[u].sum = tr[u].sum + (tr[u].r - tr[u].l + 1) * add

再区间更新时,可以把乘和加统一成一个操作:tr[u].sum = tr[u].sum * mul + (tr[u].r - tr[u].l + 1) * add(加操作时mul设置为1,乘操作时add设置为0)

上面解决了sum修改的问题,接下来,就要看mul、add如何修改,关键在于要考虑mul、add的优先级?

1、先加后乘

假设先执行加法,后执行乘法,那么对于懒标记mul,add,意味着对其区间每一个数x都执行(x + add) * mul,

如果再来一个加add'操作,区间每一个数变成(x + add) * mul + add',不难分析,无法通过将add、mul进行更新得到形如(x + add) * mul的形式,

所以先加后乘不可行。

2、先乘后加

假设先执行乘法,后执行加法,那么对于懒标记mul,add,意味着对其区间每一个数x都执行x * mul + add,

如果再来一个加add'操作,区间每一个数变成x * mul + add + add',显然通过将add += add',即可以通过x * mul + add得到正确的结果;

如果再来一个乘mul'操作,区间每一个数变成(x * mul + add) * mul' = x * mul * mul' + add * mul',显然通过将mul *= mul', add * mul',即可以通过x * mul + add得到正确的结果。

确定了操作优先级,也就确定了懒标记的更新方式,可以将乘和加统一处理:

对于一个节点u,对其区间每个数乘mul,加add,如果只加则mul=1,如果只乘则add=0,懒标记更新方式为:

tr[u].mul = tr[u].mul * mul

tr[u].add = tr[u].add * mul + add
修改节点信息代码为:
void addtag(int u, LL mul, LL add)
{tr[u].sum = (tr[u].sum * mul + (tr[u].r - tr[u].l + 1) * add) % m;tr[u].mul = tr[u].mul * mul % m;tr[u].add = (tr[u].add * mul + add) % m;
}

最后要注意的还是开long long。

100分代码:

#include <bits/stdc++.h>
using namespace std;typedef long long LL;const int N = 100005;struct Node 
{int l, r;LL sum; //区间和LL mul; //懒标记,子节点区间每个数乘上mul,默认值为1LL add; //懒标记,子节点区间每个数加上add,默认值为0
} tr[N * 4];
LL a[N];
int n, q, m;void pushup(int u)
{tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % m;
}void build(int u, int l, int r)
{tr[u] = {l, r, 0, 1, 0};if(l == r) tr[u].sum = a[l];else{int mid = l + r >> 1;build(u << 1, l, mid);build(u << 1 | 1, mid + 1, r);pushup(u);}
}void addtag(int u, LL mul, LL add)
{tr[u].sum = (tr[u].sum * mul + (tr[u].r - tr[u].l + 1) * add) % m;tr[u].mul = tr[u].mul * mul % m;tr[u].add = (tr[u].add * mul + add) % m;
}void pushdown(int u)
{addtag(u << 1, tr[u].mul, tr[u].add);addtag(u << 1 | 1, tr[u].mul, tr[u].add);tr[u].mul = 1;tr[u].add = 0;
}LL query(int u, int l, int r)
{if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;else if(tr[u].l > r || tr[u].r < l) return 0;else{pushdown(u);return (query(u << 1, l, r) + query(u << 1 | 1, l, r)) % m;}
}void update(int u, int l, int r, LL mul, LL add)
{if(tr[u].l >= l && tr[u].r <= r) addtag(u, mul, add);else if(tr[u].l > r || tr[u].r < l) return;else {pushdown(u);update(u << 1, l, r, mul, add);update(u << 1 | 1, l, r, mul, add);pushup(u);}
}int main()
{cin >> n >> q >> m;for(int i = 1; i <= n; i++) cin >> a[i];build(1, 1, n);int op, x, y, k;while(q--){cin >> op >> x >> y;if(op == 1) {cin >> k;update(1, x, y, k, 0); //乘k加0}else if(op == 2){cin >> k;update(1, x, y, 1, k); //乘1加k}else cout << query(1, x, y) << endl;}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/843519.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++下的gRPC与protobuf使用和介绍

目录gRPC允许定义四类服务方法流是会结束的stream(流式传输)编写流程客户端使用 ClientReader客户端使用 ClientWriter客户端使用 ClientReaderWriter服务器端gRPC允许定义四类服务方法一元RPC:客户端发送一次请求,等待服务端响应结构,会话结束,就像一次普通的函数调用这…

uniapp 微信小程序 子组件行内样式通过父组件参数获取

uniapp中正常按vue写法没问题,但是编译成微信小程序时,style中会变成[object object],如下图 子组件可以通过计算属性处理一下传进来的style对象,代码如下<template><div><div>我是自定义组件</div><div :style="generateStyle">00{{t…

HuggingFace入门与实践

现在全民AI大模型,虽然我不是算法工程师,但是作为IT从业者,多少应该了解一下。然而,论文太多,原理太难,那咱们就从实践开始,先实践看效果,再学习研究原理。 1. 存在价值及原因简而言之:HuggingFace是菜鸟的福音,大佬的舞台,学术与工程的桥梁!平台链接:https://hug…

Filter内存马

概述 最近感冒了,不想BB太多,直接开始调试吧,先写个Filter来调试 Filter代码 新建一个FilterShell类,代码如下: 一个类如果想要成为Filter则需要继承Filter,然后重写init、doFilter、destory这三个方法,分别表示了init::Filter在初始化时被调用 doFilter:在Filter被命…

探索 TypeScript 编程的利器:ts-morph 入门与实践

我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。本文作者:贝儿背景 在开发 web IDE 中生成代码大纲的功能时, 发现自己对 TypeScript 的了解知之甚少,以至于针对该功能的实现没有明确的思…

RK3562J正式支持NPU,性价比再提升!

RK3562J是瑞芯微最新推出的一款超高性价比工业处理器,四核Cortex-A53@1.8GHz + Cortex-M0@200MHz异构多核架构,并支持十路UART、两路CAN、两路网口、三种显示、双路Camera等,外设接口资源十分丰富,是RK3568J处理器降成本、降功耗的首选平台,在工商业储能EMS、通讯管理机、…

Movie相关

IDA-VLM: Towards Movie Understanding via ID-Aware Large Vision-Language Model 故事:现在的LVLM只能处理单场景,跨场景中关联实体的能力不行。比如电影中同一个角色在不同场景中出现,现有的LVLM不能把相同角色合并。所以本文提出了一个benchmark衡量跨场景角色对齐能力,…

PHY6236超低成本低功耗蓝牙芯片智能灯控家居

超低成本SOC蓝牙芯片PHY6236PHY6236 是一款用于低功耗蓝牙和专有 2.4G 应用的片上系统 (SoC)。它具有高性能低功耗 32 位 RISC-V MCU,具有 8KB 保留 SRAM、80KB ROM、8KB OTP 和超低功耗、高性能、多模式无线电。此外,PHY6236 还可以支持具有安全性和应用的 BLE。串行外设 IO…

20222411 2024-2025-1 《网络与系统攻防技术》实验五实验报告

1.实验内容 1.1 实践内容 (1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息:DNS注册人及联系方式、该域名对应IP地址、IP地址注册人及联系方式、IP地址所在国家、城市和具体地理位置 PS:使用whois、dig、nslookup、traceroute、以及…

如何通过精准管理,推动产品按时交付

作为产品经理,项目管理是一项必须具备的核心能力。无论是从产品规划、开发到最终交付,项目管理贯穿了整个产品生命周期,涉及团队协调、进度控制、资源分配、质量保障等多个方面。有效的项目管理不仅能帮助团队按时交付高质量的产品,还能提升效率、降低成本并确保客户满意。…

js和CSS3媒体查询制作简单的响应式导航菜单

这是一款使用纯js和css3媒体查询制作的简单的响应式导航菜单效果。该导航菜单类似bootstrap导航菜单,它通过media query制作760像素断点,当视口小于760像素时,菜单会收缩为隐藏的汉堡包菜单。在线演示 下载使用方法HTML结构 该导航菜单使用<nav>元素最为包裹容器,di…

hhdb数据库介绍(10-4)

实例管理 该功能用来查看和管理所有计算节点集群中存储节点所在实例的主从关系。实例信息可以通过主机名、端口号、和存储节点版本号进行筛选。 实例管理信息 功能入口: 登录管理用户界面->实例管理实例管理信息以一个存储节点为单位显示一条记录,可对具体的存储节点进行“…