【模板】线段树 2

news2024/12/18 22:11:27

题目描述

如题,已知一个数列,你需要进行下面三种操作:

  • 将某区间每一个数乘上 x x x

  • 将某区间每一个数加上 x x x

  • 求出某区间每一个数的和

输入格式

第一行包含三个整数 n , m , p n,m,p n,m,p,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i 项的初始值。

接下来 m m m 行每行包含若干个整数,表示一个操作,具体如下:

操作 1 1 1: 格式:1 x y k 含义:将区间 [ x , y ] [x,y] [x,y] 内每个数乘上 k k k

操作 2 2 2: 格式:2 x y k 含义:将区间 [ x , y ] [x,y] [x,y] 内每个数加上 k k k

操作 3 3 3: 格式:3 x y 含义:输出区间 [ x , y ] [x,y] [x,y] 内每个数的和对 p p p 取模所得的结果

输出格式

输出包含若干行整数,即为所有操作 3 3 3 的结果。

样例 #1

样例输入 #1

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

样例输出 #1

17
2

提示

【数据范围】

对于 30 % 30\% 30% 的数据: n ≤ 8 n \le 8 n8 m ≤ 10 m \le 10 m10
对于 70 % 70\% 70% 的数据:$n \le 10^3 , , m \le 10^4$
对于 100 % 100\% 100% 的数据:$ n \le 10^5 , , m \le 10^5$

除样例外, p = 571373 p = 571373 p=571373

(数据已经过加强qwq)

样例说明:

故输出应为 17 17 17 2 2 2 40   m o d   38 = 2 40 \bmod 38 = 2 40mod38=2

解题思路:

关于线段树,这里简单说明一下

首先是线段树的结构,因为用指针存储树的结构过于麻烦,所以用数组进行树的结构存储

初始化,为根节点分配索引 1 1 1

设根节点索引为root,左子树索引为left,右子树索引为right

则有left = root * 2right = root * 2 + 1

然后你会发现每层最后一个节点的索引分别为 1 1 1 3 3 3 7 7 7 15 15 15

也就是 2 1 − 1 2^1-1 211 2 2 − 1 2^2 - 1 221 2 3 − 1 2^3 - 1 231 2 4 − 1 2^4 - 1 241…,挺神奇的

所以我们为线段树维护的节点数量为区间长度$ * 4$

关于节点的数据,每个节点维护一段数组区间

左子树和右子树各自维护根节点的一半区间

维护的可以是区间的最大/最小值、区间和等

然后关于线段树的三大操作:建立、更新、查询,这里不详细展开

其核心思路就是先不断向下搜索确定子节点,然后递归更新根节点

如果直接看代码不太懂的话,一会我会推荐一篇我认为写得很好的算法说明

最后是比较难懂的懒惰标记(就是代码中的mul_tagadd_tag

它的功能就是像名字一样,是用来偷懒的

更新到某个节点(该节点维护的区间为更新区间的真子集)之后停止更新,而是打上标记

如果之后需要用到它的子节点,那么就继续更新,这样可以减少操作量,提高效率

生动形象的话就是“工作你检查到哪里我就做到哪里”

这里是一个讲解的非常好的线段树说明(我就是从这里学的):线段树

本题有点难是因为有两个懒惰标记:加法标记和乘法标记

我们需要确定更新子树的时候这两个标记的操作顺序

从而决定这两个标记本身的更新顺序

比较简单的是先乘法后加法的顺序更新子树,先加后乘可以自行尝试

如果是操作 1 1 1,那么将两个标记同时乘上操作数即可

如果是操作 2 2 2,只需要把加法标记加上操作数,甚至不需要更新乘法标记

这里需要注意的一点是所有乘法标记最开始需要初始化为 1 1 1

但是在运算过程中,由于取模操作,乘法标记可能为 0 0 0

所以,懒惰标记是否传递的判断应该是mul_tag != 1

其余判断均会导致一些更新错误

那么,AC代码如下

#include <iostream>
using namespace std;
const int max_n = int(1e5);
const int max_m = int(1e5);

int n, m;
long long p;
long long num_arr[max_n + 1];
long long tree[max_n * 4 + 1];
long long mul_tag[max_n * 4 + 1];
long long add_tag[max_n * 4 + 1];


void push_down(int index, int l, int r) {
	if (mul_tag[index] != 1 || add_tag[index]) {
		long long mul = mul_tag[index];
		long long add = add_tag[index];
		int m = l + ((r - l) >> 1);

		tree[index << 1] = ((tree[index << 1] * mul) + add * (long long)(m - l + 1)) % p;
		mul_tag[index << 1] = (mul * mul_tag[index << 1]) % p;
		add_tag[index << 1] = (add + add_tag[index << 1] * mul) % p;

		tree[(index << 1) + 1] = ((tree[(index << 1) + 1] * mul) + add * (long long)(r - m)) % p;
		mul_tag[(index << 1) + 1] = (mul * mul_tag[(index << 1) + 1]) % p;
		add_tag[(index << 1) + 1] = (add + add_tag[(index << 1) + 1] * mul) % p;

		mul_tag[index] = 1;
		add_tag[index] = 0;
	}
}

void build_tree(int index, int l, int r) {
	if (l == r) {
		tree[index] = num_arr[l] % p;
		return;
	}
	else {
		int m = l + ((r - l) >> 1);
		build_tree(index << 1, l, m);
		build_tree((index << 1) + 1, m + 1, r);
		tree[index] = (tree[index << 1] + tree[(index << 1) + 1]) % p;
	}
}

void update_1(int index, int l, int r, const long long mul, const int L, const int R) {
	if (L <= l && r <= R) {
		tree[index] = (mul * tree[index]) % p;
		mul_tag[index] = (mul * mul_tag[index]) % p;
		add_tag[index] = (mul * add_tag[index]) % p;
		return;
	}
	else {
		push_down(index, l, r);

		int m = l + ((r - l) >> 1);
		if (L <= m)
			update_1(index << 1, l, m, mul, L, R);
		if (m + 1 <= R)
			update_1((index << 1) + 1, m + 1, r, mul, L, R);

		tree[index] = (tree[index << 1] + tree[(index << 1) + 1]) % p;
	}
}

void update_2(int index, int l, int r, const long long add, const int L, const int R) {
	if (L <= l && r <= R) {
		tree[index] = ((long long)(r - l + 1) * add + tree[index]) % p;
		add_tag[index] = (add_tag[index] + add) % p;
		return;
	}
	else {
		push_down(index, l, r);

		int m = l + ((r - l) >> 1);
		if (L <= m)
			update_2(index << 1, l, m, add, L, R);
		if (m + 1 <= R)
			update_2((index << 1) + 1, m + 1, r, add, L, R);

		tree[index] = (tree[index << 1] + tree[(index << 1) + 1]) % p;
	}
}

long long search(int index, int l, int r, const int L, const int R) {
	if (L <= l && r <= R) {
		return tree[index];
	}
	else {
		push_down(index, l, r);

		int m = l + ((r - l) >> 1);
		long long left_ret = 0, right_ret = 0;

		if (L <= m)
			left_ret = search(index << 1, l, m, L, R);
		if (m + 1 <= R)
			right_ret = search((index << 1) + 1, m + 1, r, L, R);

		return (left_ret + right_ret) % p;
	}
}

int main() {
	for (int i = 1; i <= max_n * 4; i++) mul_tag[i] = 1;

	cin >> n >> m >> p;
	for (int i = 1; i <= n; i++) cin >> num_arr[i];

	build_tree(1, 1, n);

	int q[3];
	long long num;
	for (int i = 1; i <= m; i++) {
		cin >> q[0];
		if (q[0] == 1) {
			cin >> q[1] >> q[2] >> num;
			update_1(1, 1, n, num % p, q[1], q[2]);
		}
		else if (q[0] == 2) {
			cin >> q[1] >> q[2] >> num;
			update_2(1, 1, n, num % p, q[1], q[2]);
		}
		else {
			cin >> q[1] >> q[2];
			cout << search(1, 1, n, q[1], q[2]) << endl;
		}
	}
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络笔记(复试准备)第一章

计算机网络笔记&#xff08;复试准备&#xff09; 第一章 网络&#xff0c;互联网与因特网 网络由若干个结点和连接这些结点的链路组成 多个网络通过路由器连接起来这也就形成了一个更大的网络即是我们熟知的互联网也就是“网络的网络” 因特网是世界上最大的网络 问&#xf…

Open-Vocabulary Object Detection Using Captions论文讲解

文章目录一、论文前言二、提出原因三、论文的核心四、论文讲解4.1 论文流程4.2 OVD与之前相关的setting4.3 结果对比一、论文前言 目标检测是人工智能最突出的应用之一&#xff0c;也是深度学习最成功的任务之一。 然而&#xff0c;尽管深度对象检测取得了巨大进步&#xff0…

MongoDB在银行海量历史订单交易数据查询中的应用(Spring boot + Bee)

MongoDB在银行海量历史订单交易数据查询中的应用(Spring boot Bee) 近年来,随着各种便捷支付方式的普及,银行账户交易数据呈现爆炸式增长,同时数据模型也在不断变化,传统关系型数据库已难以满足这种海量的、模式灵活、高可用、高性能的数据存储和查询需求。通过对银行历史交易…

【编程入门】应用市场(php版)

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 《N种编程语言做个记事本》 目标 为编程初学者打造入门学习项目&#xff0c;使…

【MySQL】索引常见面试题

文章目录索引常见面试题什么是索引索引的分类什么时候需要 / 不需要创建索引&#xff1f;有什么优化索引的方法&#xff1f;从数据页的角度看B 树InnoDB是如何存储数据的&#xff1f;B 树是如何进行查询的&#xff1f;为什么MySQL采用B 树作为索引&#xff1f;怎样的索引的数…

033_SS_Inversion-Based Creativity Transfer with Diffusion Models

下载地址&#xff1a;Arxiv 2022.11.23 Code地址&#xff1a;https://github.com/zyxElsa/creativity-transfer 1. Introduction Motivations 以前的任意示例引导的艺术图像生成方法&#xff08;比如风格迁移&#xff09;通常无法控制形状变化或传达语义元素。而预训练的text…

【Linux | ELK 8.2】搭建ELKB集群Ⅰ—— 实验环境说明和搭建Elasticsearch集群

目录1. 实验环境1.1 实验工具1.2 操作系统1.3 架构版本、IP地址规划与虚拟机配置要求1.4 拓扑图1.5 其他要求2. 实验步骤2.1 安装Elasticsearch&#xff08;单节点&#xff09;&#xff08;1&#xff09;检查系统jdk版本&#xff08;2&#xff09;下载elasticsearch&#xff08…

格式化串漏洞

格式化字符串漏洞本身并不算缓冲区溢出漏洞&#xff0c;这里作为比较典型的一类漏洞进行简单介绍。为了能够将字符串、变量、地址等数据按照指定格式输出&#xff0c;通常使用包含格式化控制符的常量字符串作为格式化串&#xff0c;然后指定用相应变量来代替格式化串中的格式化…

进程管理之基本概念

目录 关于进程的基本概念 进程描述符 查看进程 进程标识 进程的生命周期 僵尸进程、孤儿进程 写时拷贝技术 fork()函数 vfork()函数 终止进程 进程优先级和权重 进程地址空间 关于进程的基本概念 进程和程序是操作系统领域的两个重要的概念&#xff0c;进程是执行…

LeetCode 145. 二叉树的中序遍历

LeetCode 145. 二叉树的中序遍历 难度&#xff1a;easy\color{Green}{easy}easy 题目描述 给你一棵二叉树的根节点 rootrootroot &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1]示例 2&#xff1a…

mitmproxy使用总结

mitmproxy is a free and open source interactive HTTPS proxy. 这官网上的一句话说明mitmproxy的身份&#xff0c;MITM 即中间人攻击&#xff08;Man-in-the-middle attack&#xff09;&#xff0c;与charles、fidder之类的抓包工具不同的是可以增加一些自定义处理的扩展脚本…

aws appmesh 在ec2上部署和使用appmesh

参考资料 Getting started with AWS App Mesh and Amazon EC2 之前的文章中我们已经介绍了aws的服务网格场频appmesh&#xff0c;并且在eks环境中进行了部署和简单功能的测试。由于eks环境较为复杂&#xff0c;本文在ec2环境下手动配置appmesh网格环境 需求&#xff1a; 两个…

【Spring 基础】

【Spring 基础】 一、 Spring 介绍 1. 简述 Spring 技术是 JavaEE 开发必备技能&#xff0c;企业开发技术选型专业角度 简化开发&#xff0c;降低企业级开发的复杂性 IoCAOP 事务处理 框架整合&#xff0c;高效整合其他技术&#xff0c;提高企业级应用开发与运行效率 MyBat…

Linux内核中的软中断、tasklet和工作队列

软中断、tasklet和工作队列并不是Linux内核中一直存在的机制&#xff0c;而是由更早版本的内核中的“下半部”&#xff08;bottom half&#xff09;演变而来。下半部的机制实际上包括五种&#xff0c;但2.6版本的内核中&#xff0c;下半部和任务队列的函数都消失了&#xff0c;…

5M240ZT144C5N【CPLD】5M240ZT144I5N,5M570ZT100I5N满足低功耗设计

MAX V设备系列的特点&#xff1a;低成本、低功耗、非易失性CPLD架构即时启动(0.5 ms或更短)配置时间待机电流低至25A&#xff0c;快速下电/复位操作快速传播延迟和时钟到输出时间内部振荡器模拟RSDS输出支持&#xff0c;数据速率高达200 Mbps模拟LVDS输出支持&#xff0c;数据速…

手把手教你做微信公众号

手把手教你做微信公众号 微信公众号可以通过注册的方式来建立。 1.进入微信公众平台 首先&#xff0c;在浏览器中搜索微信公众号&#xff0c;网页第一个就是&#xff0c;如下图所示&#xff0c;我们点进去。 2.注册微信平台账号 进入官网之后&#xff0c;如下图所示&#…

day53【代码随想录】单调栈之每日温度、下一个更大元素 I、下一个更大元素 II

文章目录前言一、每日温度&#xff08;力扣739&#xff09;二、下一个更大元素 I&#xff08;力扣496&#xff09;三、下一个更大元素 II&#xff08;力扣503&#xff09;【环形数组】思路一思路二前言 单调栈&#xff1a;栈内元素保证递增或递减的 1、每日温度 2、下一个更大…

“AI板块凉了”说法有失公允?AI板块CNTM其发展的关键!

今年区块链所有的建设都围绕着以太坊&#xff0c;存储板块开年也是火爆了一把&#xff0c;龙头FIL更是一路前行&#xff0c;短期虽有回落但热度依然在&#xff0c;后期市场热度还是会给到存储&#xff0c;未来可期。目前市场上新出一个区块链覆盖多个赛道的项目——Filswan和AI…

Hive的视图与索引

Hive的视图其实是一个虚表&#xff0c;视图可以允许保存一个查询&#xff0c;并像对待表一样对这个查询进行操作&#xff0c;视图是一个逻辑结构&#xff0c;并不会存储数据。 Hive中的索引只有有限的功能&#xff0c;Hive中没有主键和外键的概念&#xff0c;可以通过对一些字段…

【CS224W】(task6)Google的PageRank算法

note 求解pagerank&#xff1a;用power iteration&#xff08;幂迭代&#xff09;方法求解 rM⋅r\mathbf{r}\mathbf{M} \cdot \mathbf{r}rM⋅r ( MMM 是重要度矩阵)用random uniform teleporation解决dead-ends&#xff08;自己指向自己&#xff09;和spider-traps&#xff08…