洛谷P3372 【模板】线段树 1以及分块

【模板】线段树 1

题目描述

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

  1. 将某区间每一个数加上 k k k
  2. 求出某区间每一个数的和。

输入格式

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

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

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

  1. 1 x y k:将区间 [ x , y ] [x, y] [x,y] 内每个数加上 k k k
  2. 2 x y:输出区间 [ x , y ] [x, y] [x,y] 内每个数的和。

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

11
8
20

提示

对于 30 % 30\% 30% 的数据: n ≤ 8 n \le 8 n8 m ≤ 10 m \le 10 m10
对于 70 % 70\% 70% 的数据: n ≤ 10 3 n \le {10}^3 n103 m ≤ 10 4 m \le {10}^4 m104
对于 100 % 100\% 100% 的数据: 1 ≤ n , m ≤ 10 5 1 \le n, m \le {10}^5 1n,m105

保证任意时刻数列中所有元素的绝对值之和 ≤ 10 18 \le {10}^{18} 1018

【样例解释】

#

思路

先不要看算法标签和题目名称。
通过观察可以发现,如果强行枚举,绝对会超时(不会有玄学方法能过吧
看题目的数据范围, 1 ≤ n , m ≤ 10 5 1 \le n, m \le {10}^5 1n,m105
那么这道题目时间复杂度的最高 O ( n n ) O(n\sqrt n) O(nn )

这道题目明显做法很多,线段树、树状数组可以用十分优秀的 O ( n log ⁡ n ) O(n\log n) O(nlogn)的时间复杂度通过。
但是明显线段树、树状数组这些做法太长了不好写
因此,分块成了一种简单好写,而且时间复杂度较为优秀的思想。
分块的时间复杂度略高于线段树、树状数组,为 O ( n n ) O(n\sqrt n) O(nn ),所以分块可以在这一题替代线段树。

分块原理

先考虑暴力,最简单的思路就是每一次操作进行增加就从 l l l枚举到 r r r,增加每一个数,求和就从 l l l枚举到 r r r,进行累加。(这里的 l l l r r r代表题目中的 x x x y y y
显然时间大大滴超。
导致超时的情况是 l l l r r r的差值很大,接下来考虑如何优化掉这种情况。
可以将数组分成很多
l l l r r r的差值很大的情况下,这个区间将会覆盖很多整块。
比如 n = 1000 n=1000 n=1000的情况下,每个块的大小为 100 100 100时,假如 l = 10 l=10 l=10 r = 500 r=500 r=500时,这个区间就可以看作4个完整块以及一个不完整的块,如果可以在 O ( 1 ) O(1) O(1)的时间将每个完整块处理,那么这次操作的时间复杂度就会降到 O ( n ÷ 10 ) O(n÷10) O(n÷10)左右。

分块的块的大小

在面对并不在一个完整的块内的情况,只能进行暴力求解,设块的大小为 s i z siz siz,则时间复杂度为 O ( s i z ) O(siz) O(siz)
覆盖多个完整块的情况下,每个完整块都是 O ( 1 ) O(1) O(1),设共有 n u m num num块,则时间复杂度为 O ( n u m ) O(num) O(num)
因为块数=总数÷块的大小,因此 n u m = n / s i z , n u m ∗ s i z = n num=n/siz,num*siz=n num=n/siznumsiz=n
为了让时间复杂度尽可能低,要 n u m num num s i z siz siz尽可能都小,此时最好的办法就是将 s i z siz siz n u m num num设为 n \sqrt n n
因此块的大小最好为 n \sqrt n n
此时的时间复杂度为 m n m\sqrt n mn 其中 m m m为操作次数, n n n为元素个数。

这道题的分块实现

所需的数组和变量

ll siz,num;//块个数和块大小
ll L[N],R[N];//每个块的左右端点
ll bel[N],su[N],add[N];//每个元素属于哪一个块,以及每个块的和、每个块每个元素都加上多少
ll n,m,a[N];//对应输入

分块初始化

void init(){siz=sqrt(n);//最佳的分块大小num=n/siz+(n%siz>0);//块的个数for(int i=1;i<=num;i++){//这里预处理,其实也可以封装函数后面计算L[i]=siz*(i-1)+1;R[i]=min(n,siz*i);}for(int i=1;i<=n;i++){//这里也是预处理bel[i]=(i-1)/siz+1;su[bel[i]]+=a[i];}
}

预处理可以降低常数

区间增加某个数

void upd(ll l,ll r,ll k){ll x=bel[l],y=bel[r];if(x==y){//在同一块内的情况for(int i=l;i<=r;i++){a[i]+=k;su[x]+=k;}}else{for(int i=x+1;i<y;i++){//整块add[i]+=k;su[i]+=k*siz;}for(int i=l;i<=R[x];i++){//非完整a[i]+=k;su[x]+=k;}for(int i=L[y];i<=r;i++){//非完整a[i]+=k;su[y]+=k;}}
}

这里可以看作每一个块内所有元素都加上的某个数暂时没有加上去,而是保留到需要用的时候再进行处理。
面对不完整的块直接暴力就行。

区间求和

ll qu(ll l,ll r){ll ans=0;//记录答案ll x=bel[l],y=bel[r];if(x==y){//同一个块内直接暴力就行for(int i=l;i<=r;i++){ans+=a[i]+add[x];//加上add是因为把之前没有加上的加上}}else{for(int i=x+1;i<y;i++){ans+=su[i];//每个块的和之前记录了}for(int i=l;i<=R[x];i++){ans+=a[i]+add[x];//这里也是一样}for(int i=L[y];i<=r;i++){ans+=a[i]+add[y];//同上}}return ans;
}

查找时,之前没有加上去放在add数组里的值就可以加上了,优化了时间复杂度。
可以看出分块还是一种暴力。
这里也可以看出预处理的作用。

“完整”代码

直接复制代码不是一个好习惯。

ll siz,num,L[N],R[N],bel[N],su[N],add[N];
ll n,m,a[N];
void init(){siz=sqrt(n);num=n/siz+(n%siz>0);for(int i=1;i<=num;i++){L[i]=siz*(i-1)+1;R[i]=min(n,siz*i);}for(int i=1;i<=n;i++){bel[i]=(i-1)/siz+1;su[bel[i]]+=a[i];}
}
void upd(ll l,ll r,ll k){ll x=bel[l],y=bel[r];if(x==y){for(int i=l;i<=r;i++){a[i]+=k;su[x]+=k;}}else{for(int i=x+1;i<y;i++){add[i]+=k;su[i]+=k*siz;}for(int i=l;i<=R[x];i++){a[i]+=k;su[x]+=k;}for(int i=L[y];i<=r;i++){a[i]+=k;su[y]+=k;}}
}
ll qu(ll l,ll r){ll ans=0;ll x=bel[l],y=bel[r];if(x==y){for(int i=l;i<=r;i++){ans+=a[i]+add[x];}}else{for(int i=x+1;i<y;i++){ans+=su[i];}for(int i=l;i<=R[x];i++){ans+=a[i]+add[x];}for(int i=L[y];i<=r;i++){ans+=a[i]+add[y];}}return ans;
}
int main(){scanf("%lld %lld",&n,&m);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}init();for(int i=1;i<=m;i++){int op;scanf("%d",&op);if(op==1){ll x,y,k;scanf("%lld %lld %lld",&x,&y,&k);upd(x,y,k);}else{ll x,y;scanf("%lld %lld",&x,&y);ll tmp=qu(x,y);printf("%lld\n",tmp);}}return 0;
}

分块和线段树对比的优势和劣势

时间复杂度上

线段树的时间复杂度平均 O ( n log ⁡ n ) O(n\log n) O(nlogn)
分块时间复杂度 O ( n n ) O(n\sqrt n) O(nn )
分块时间复杂度较高

空间复杂度上

线段树和分块的空间复杂度均为 O ( n ) O(n) O(n),but实际上分块的空间更小,不容易被卡。

代码复杂度上

d a l a o dalao dalao们的线段树代码100行左右。
分块80行左右,代码量要少。

线段树的思路比较难理解。
分块的思路就是暴力,十分容易理解,分块更好。

结果

可以看出分块与线段树不相上下,面对大部分区间问题分块足以。不行就用莫队

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

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

相关文章

Linux运维之Linux的安装和配置

目录 Linux的基本概念&#xff1a; 1.为什么要使用Linux&#xff1f; 2.什么是Linux&#xff1f; Linux的安装和配置&#xff1a; 1.下载Linux的虚拟机和镜像文件&#xff1a; 1.1下载虚拟机 1.2下载镜像文件 2.在虚拟机或者物理机中安装Linux操作系统 3.配置虚拟机的…

【ArcMap零基础训练营】01 ArcMap使用入门及绘图基础

ArcMap入门及使用技巧 230106直播录像 ArcMap使用技巧及制图入门 ArcGIS的安装 本次教学使用的ArcMap版本为10.7&#xff0c;建议各位安装ArcGIS10.0及其以上版本的英文版本。 下载及安装详细教程可参考ArcGIS 10.8 for Desktop 完整安装教程 麻辣GIS 改善使用体验的几个操作…

程序员学英文之At the Airport Customs

Dialogue-1 Making Airline Reservation预定机票 My cousin works for Xiamen Airlines. 我表哥在厦航上班。I’d like to book an air ticket. 我想预定一张机票。Don’t judge a book by its cover. 不要以貌取人。I’d like to book / re-serve a table for 10. 我想预定一…

Python 写的几个经典游戏 新年放烟花、 贪吃蛇、俄罗斯方块、超级玛丽、五子棋、蜘蛛纸牌

0、新年放烟花 import pygame import random import math# 初始化Pygame pygame.init()# 设置窗口 WIDTH 800 HEIGHT 600 screen pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("新年放烟花")# 颜色定义 BLACK (0, 0, 0) WHITE (255, 2…

Python Typing: 实战应用指南

文章目录 1. 什么是 Python Typing&#xff1f;2. 实战案例&#xff1a;构建一个用户管理系统2.1 项目描述2.2 代码实现 3. 类型检查工具&#xff1a;MyPy4. 常见的 typing 用法5. 总结 在 Python 中&#xff0c;静态类型检查越来越受到开发者的重视。typing 模块提供了一种方式…

14-8C++STL的queue容器

一、queue容器 (1)queue容器的简介 queue为队列容器&#xff0c;“先进先出”的容器 (2)queue对象的构造 queue<T>q; queue<int>que Int;//存放一个int的queue容器 queue<string>queString;//存放一个string的queue容器 (3)queue容器的push()与pop()方…

计算机毕业设计Python+CNN卷积神经网络高考推荐系统 高考分数线预测 高考爬虫 协同过滤推荐算法 Vue.js Django Hadoop 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

PyCharm接入DeepSeek实现AI编程

目录 效果演示 创建API key 在PyCharm中下载CodeGPT插件 配置Continue DeepSeek 是一家专注于人工智能技术研发的公司&#xff0c;致力于开发高性能、低成本的 AI 模型。DeepSeek-V3 是 DeepSeek 公司推出的最新一代 AI 模型。其前身是 DeepSeek-V2.5&#xff0c;经过持续的…

C语言指针专题一 -- 指针基础原理

目录 1. 指针概念 地址和变量 指针 2. 指针的声明与初始化 3. 指针的使用 指针访问 指针的运算 指针与数组 指针与函数 4. 编程实例 5. 指针的常见陷阱与防御 6. 总结 1. 指针概念 地址和变量 在C语言中&#xff0c;地址和变量是两个基本但非常重要的概念。 1. 变…

【Python】已解决:ModuleNotFoundError: No module named ‘cv2’

个人简介&#xff1a;某不知名博主&#xff0c;致力于全栈领域的优质博客分享 | 用最优质的内容带来最舒适的阅读体验&#xff01;文末获取免费IT学习资料&#xff01; &#x1f345; 文末获取更多信息 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅收藏 &#x…

从0开始,来看看怎么去linux排查Java程序故障

一&#xff0c;前提准备 最基本前提&#xff1a;你需要有liunx环境&#xff0c;如果没有请参考其它文献在自己得到local建立一个虚拟机去进行测试。 有了虚拟机之后&#xff0c;你还需要安装jdk和配置环境变量 1. 安装JDK&#xff08;以OpenJDK 17为例&#xff09; 下载JDK…

设计模式-建造者模式、原型模式

目录 建造者模式 定义 类图 优缺点 角色 建造者模式和工厂模式比较 使用案例 原型模式 定义 类图 优缺点 应用场景 应用类型 浅克隆 深克隆 建造者模式 定义 将一个复杂的对象的构造与它的表示分离&#xff0c;使同样的构建过程可以创建不同的表示&#xff0c;…

1 HDFS

1 HDFS 1. HDFS概述2. HDFS架构3. HDFS的特性4. HDFS 的命令行使用5. hdfs的高级使用命令6. HDFS 的 block 块和副本机制6.1 抽象为block块的好处6.2 块缓存6.3 hdfs的文件权限验证6.4 hdfs的副本因子 7. HDFS 文件写入过程&#xff08;非常重要&#xff09;7.1 网络拓扑概念7.…

75-《倒提壶》

倒提壶 倒提壶&#xff08;学名&#xff1a;Cynoglossum amabile Stapf et Drumm.&#xff09;&#xff1a;紫草科&#xff0c;琉璃草属多年生草本植物&#xff0c;高可达60厘米。茎密生贴伏短柔毛。基生叶&#xff0c;长圆状披针形或披针形&#xff0c;茎生叶长圆形或披针形&a…

第一个3D程序!

运行效果 CPP #include <iostream> #include <fstream> #include <string> #include <cmath>#include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/…

简要介绍C语言/C++的三目运算符

三元运算符是C语言和C中的一种简洁的条件运算符&#xff0c;它的形式为&#xff1a; 条件表达式 ? 表达式1 : 表达式2; 三元运算符的含义 条件表达式&#xff1a;这是一个布尔表达式&#xff0c;通常是一个比较操作&#xff08;如 >、<、 等&#xff09;。 表达式1&am…

本地部署DeepSeekp R1教程

目录 一.打开ollama官网&#xff0c;下载安装 1.下载完成双击安装程序 2.winr 输入cmd打开命令行输入命令 查看是否安装成功 二.部署DeepSeek R1模型 1. 下载模型&#xff1a;终端输入 (根据你的显存大小选择版本&#xff0c;16g就可以选择14b/32b)**电脑配置很低的话选…

事务04之死锁,锁底层和隔离机制原理

死锁和事务底层原理 文章目录 死锁和事务底层原理一&#xff1a;MySQL中的死锁现象1&#xff1a;何为死锁1.1&#xff1a;死锁的概念1.2&#xff1a;死锁产生的四个必要条件&#xff1a; 2&#xff1a;MySQL的死锁2.1&#xff1a;死锁的触发2.2&#xff1a;MySQL的死锁如何解决…

Fiddler(一) - Fiddler简介_fiddler软件

文章目录 一、为什么选择Fiddler作为抓包工具? 二、什么是Fiddler?三、Fiddler使用界面简介四、延伸阅读 一、为什么选择Fiddler作为抓包工具? 抓包工具有很多&#xff0c;小到最常用的web调试工具firebug&#xff0c;大到通用性强大的抓包工具wireshark。为什么使用fid…

RabbitMQ模块新增消息转换器

文章目录 1.目录结构2.代码1.pom.xml 排除logging2.RabbitMQConfig.java3.RabbitMQAutoConfiguration.java 1.目录结构 2.代码 1.pom.xml 排除logging <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/PO…