差分学习笔记

news2024/9/20 22:41:53

1.前言

同步于 c n b l o g s cnblogs cnblogs 发布。

前置芝士:

  • 基本树上操作,lca。(用于树上差分。)

如有错误,欢迎各位大佬指出。(顺便复习一下远古算法。)

2.什么是差分

我们先给定一个数组 a a a,长度为 n n n,我们可以构造一个差分数组 b b b,使得对于任意的 i ( 1 ≤ i ≤ n ) i(1\le i \le n) i(1in) ∑ j = 1 i b j = a i \displaystyle\sum_{j = 1}^{i} b_j=a_i j=1ibj=ai

那么如何构建一个普通的差分数组呢?

不难想到,我们假定 a 0 = 0 a_0=0 a0=0,则此时,对于任意的 b i b_i bi,我们令它等于 a i − a i − 1 a_i-a_{i-1} aiai1,则当我们算 ∑ j = 1 i b j \displaystyle\sum_{j=1}^{i}b_j j=1ibj 时,所有 a 1 , a 2 . . . a i − 1 a_1,a_2...a_{i-1} a1,a2...ai1 都会抵消掉,只剩下 a i a_i ai,也正好满足了我们的前提条件。

3.差分数组的最普通应用

首先,我们先引入一个例题 P2367 语文成绩。题目意思大概就是说先给你一个序列,然后在进行区间加,最后求得区间的最小值即可。

而对于这种区间加减的操作,正是差分能够大展拳脚的地方。

我们先维护一个差分数组 b b b(以后皆假设差分数组为 b b b。),先将它全部初始化为0。假设当前我们面临的操作是将 [ l , r ] [l,r] [l,r] 这个区间全部加上 x x x。由于差分的前缀和便是原数组,所以我们可以一开始将 b l + x b_l+x bl+x,但是当你在算前缀和的时候,对于 r + 1 r+1 r+1 及以后的前缀和,他都会多算一个 + x +x +x,所以,为了将其抵消掉,我们需要将 b r + 1 − x b_{r+1}-x br+1x

最后,处理完这些询问之后,我们在最后求一次前缀和即可。

可以发现,差分修改操作时间复杂度为 O ( 1 ) O(1) O(1),查询时间复杂度为 O ( n ) O(n) O(n)

最后贴上一份代码:

#include<bits/stdc++.h>
using namespace std;
int n,q;
int a[5000005],c[5000005];
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	while(q--)
	{
		int l,r,x;
		scanf("%d%d%d",&l,&r,&x);
		c[l]+=x,c[r+1]-=x;//由于是差分,将c[l]+x,但为了抵消掉它对后面的贡献,我们将 c[r+1]-x 
	}
	int minn=INT_MAX;
	for(int i=1;i<=n;++i)
	{
		c[i]+=c[i-1];//求前缀和 
		a[i]+=c[i];//原数组记得加上 
		minn=min(minn,a[i]);//最小值 
	}
	cout<<minn<<endl;
}

4.差分数组的二维形式

我们上述的,全都是一个序列(一维)的情况,但是,差分仍然可以扩展到二维。(对于其定义,与一维相类似,这里不做过多赘述)

假设我们当前修改的二维区间为 ( x 1 , y 1 ) (x1,y1) (x1,y1) ( x 2 , y 2 ) (x2,y2) (x2,y2),加上 x x x x 1 ≤ x 2 , y 1 ≤ y 2 x1\le x2,y1\le y2 x1x2,y1y2)。显然,我们一开始仍然需要将起始位置 b x 1 , y 1 + x b_{x1,y1}+x bx1,y1+x。但随即我们可以发现,对于所有 x 1 − n , y 1 − n x1-n,y1-n x1n,y1n 它的值都被加上了 x x x,但这个区间实际只能管到 ( x 2 , y 2 ) (x2,y2) (x2,y2),所以,对于 ( x 1 , y 2 + 1 ) (x1,y2+1) (x1,y2+1) 以及 ( x 2 + 1 , y 1 ) (x2+1,y1) (x2+1,y1) 以后的所有格子都是当前加不到的,所以我们又将 b x 1 , y 2 + 1 − x , b x 2 + 1 , y 1 − x b_{x1,y2+1}-x,b_{x2+1,y1}-x bx1,y2+1x,bx2+1,y1x。但随即我们又可以发现,虽然减是减了,但对于 ( x 2 + 1 , y 2 + 1 ) (x2+1,y2+1) (x2+1,y2+1) 及以后的值,在差分算前缀和时被减了两次,所以我们需要将 b x 1 + 1 , y 2 + 1 + x b_{x1+1,y2+1}+x bx1+1,y2+1+x

下面配上一个图方便理解。(图略丑,勿喷。)

在这里插入图片描述

假设我们要区间加 ( 2 , 2 ) − ( 4 , 4 ) (2,2)-(4,4) (2,2)(4,4),其中黄色表示被 c x 1 , x 2 c_{x1,x2} cx1,x2 影响到的范围,蓝色表示 c x 1 , x 2 c_{x1,x2} cx1,x2 加后多影响到的地方,及 b x 1 , y 2 + 1 − x , b x 2 + 1 , y 1 − x b_{x1,y2+1}-x,b_{x2+1,y1}-x bx1,y2+1x,bx2+1,y1x 影响到的地方,绿色表示被黄色蓝色一起影响,最终被多减了一次,需要加 x x x 的区域。

大概就是:

void chafen(int x1,int y1,int x2,int y2,int x)
{
	b[x1][y1]+=x;
	b[x1][y2+1]-=x;
	b[x2+1][y1]-=x;
	b[x1+1][y2+1]+=x;
}

最后还是给一个比较简单的例题吧。P3717 [AHOI2017初中组]cover,虽然可以不用二维差分做,但当一个练习的板子题还是挺好的。

5.树上差分

这是一种非常常考也非常实用的一种差分形式。

我们先给出一种最基本的树上差分形式。即我们现在要完成的是将 x − y x-y xy 的路径上的所有节点 + x +x +x

然后我们给出树上差分的定义,即我们假设第 i i i 个点的点权为 a i a_i ai,然后我们维护差分数组 b b b 表示对于任意节点 i i i,使得 i i i 的所有子节点的 b b b 之和(包括他本身)为 a i a_i ai

然后,我们来处理树上差分。首先,我们可以把 x − y x-y xy 的路径看做 x − l c a ( x , y ) − y x-lca(x,y)-y xlca(x,y)y 的路径。( l c a lca lca 的求法这里不做赘述。)然后,由于我们要将这一段的路径全部加 z z z。我们可以发现,当我们对 b x , b y b_x,b_y bx,by 分别加上 z z z,就可以满足将 x − x- x 根节点的路径以及 y − y- y 根节点的路径全部 + z +z +z,但我们发现,不仅 f a l c a ( x , y ) − fa_{lca(x,y)}- falca(x,y) 根节点的路径多加了两遍 x x x,而且 l c a lca lca 这个节点被加了两次,但他只能被加一次,所以它也多加了一次。为了将这些效果抵消,我们可以在 b l c a ( x , y ) − z b_{lca(x,y)}-z blca(x,y)z,则对于 l c a ( x , y ) − lca(x,y)- lca(x,y) 根节点的路径,我们都被抵消了一次 z z z。但是,在抵消之后, f a l c a ( x , y − fa_{lca(x,y}- falca(x,y 根节点的路径我们仍然多加了一次 z z z,所以此时,我们需要将 b f a l c a ( x , y ) − z b_{fa_{lca(x,y)}}-z bfalca(x,y)z,便可以完美抵消掉了!

核心代码:

void tree(int x,int y,int z)
{
	b[x]+=z,b[y]+=z;
	b[lca(x,y)]-=z;b[fa[lca(x,y)]]-=z;
}

最后再奉上一个比较好想的例题:P6869 [COCI2019-2020#5] Putovanje

6.后记

虽然在维护序列时,我们完全可以用线段树树状数组等一列数据结构来代替差分这种查询较慢的结构,但差分终究还是一个好写好想的算法,是不容易出错的。毕竟,如果考场上你在面临树上路径的操作时,不会树上差分,打一个码量极大还容易错的的树链剖分就太吃亏了。

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

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

相关文章

AR增强现实技术解决企业远程协作需求

随着科技的不断发展&#xff0c;AR(增强现实)远程协同系统已经成为了一种新型的工作方式。这种系统利用AR技术将虚拟信息叠加到现实世界中&#xff0c;从而实现异地高效协作。 由广州华锐互动开发的AR远程协同系统&#xff0c;广泛应用于各个行业的远程协作场景中&#xff0c;…

44. 通配符匹配(从暴力递归到动态规划)

题目链接&#xff1a;力扣 所有的动态规划都可以使用暴力递归求解&#xff0c;如果推导dp方程比较困难&#xff0c;可以先使用暴力递归进行尝试&#xff0c;然后将从递归改为动态规划&#xff0c;这种方式在dp方程求解困难的情况下非常有效&#xff0c;而且从递归修改为动态规划…

计算机网络?

那么这样能通过审核吗&#xff1f;

二次元古代美女【InsCode Stable Diffusion美图活动一期】

二次元古代美女【InsCode Stable Diffusion美图活动一期】 一、前言二、初识 InsCode三、 试玩 Stable Diffusion 模型1.阅读Stable Diffusion 模型在线引导说明2.实际体验 Stable Diffusion 模型 四、模型相关版本和参数配置&#xff1a;五、图片生成提示词与反向提示词六、种…

游戏术语英语

王者荣耀英文术语大全&#xff01;玩这么久你都听懂了吗&#xff1f; 王者荣耀AP、AD、ADC、AOE等专业术语大全_乐游网 Operating System win2003, winXP, win7, win10 MacOS Game Platform 游戏平台 TGP&#xff08;Tencent Game Platform &#xff09; PC &#xff08;Per…

Linux上部署docker与docker-compose的步骤

Centos上部署docker与docker-compose的步骤 linux系统版本为Centos7.2 第一步-检查前置条件是否符合部署docker 64-bit 系统 kernel 3.10 使用uname -r 检查内核版本&#xff0c;返回的值大于3.10即可。 Centos 7.2的kernel是&#xff1a;3.10.0-327&#xff0c;刚好满足条件…

【算法与数据结构】225、LeetCode用队列实现栈

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;第一种解法是利用两个队列&#xff0c;一个用作输出队列&#xff0c;一个用作备份队列。主要难点在于p…

<Java导出Excel> 4.0 Java实现Excel动态模板字段增删改查

思路&#xff1a; 主要是同时操作两张表&#xff1a;一张存储数据的表&#xff0c;一张存储模板字段的表&#xff1b; 查询&#xff1a;只查询模板字段的表&#xff1b; 新增&#xff0c;修改&#xff0c;删除&#xff1a;需要同时操作两张表中的字段 如果两张表字段不一致&…

51单片机--点亮LED灯和流水灯

文章目录 前言LED模块的原理点亮一个LED灯LED灯的闪烁LED流水灯 前言 大家好&#xff0c;这里是诡异森林。我使用的是普中科技的A2的51开发板&#xff0c;适合新手入门。用到的应用是Keil5和Stc-isp&#xff0c;第一个软件主要用来写代码的&#xff0c;第二个是将代码程序输送…

RocketMQ5.0--部署与实例

RocketMQ5.0–部署与实例 一、Idea调试 1.相关配置文件 在E:\rocketmq创建conf、logs、store三个文件夹。从RocketMQ distribution部署目录中将broker.conf、logback_namesrv.xml、logback_broker.xml文件复制到conf目录。如下图所示。 其中logback_namesrv.xml、logback_b…

2.2.cuda驱动API-初始化和检查的理解,CUDA错误检查习惯

目录 前言1. cuInit-驱动初始化2. 返回值检查总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记 本次课程学习精简 CUDA 教程-Driver API 案例…

氢燃料电池汽车储氢技术及其发展现状

摘要&#xff1a; 氢能的发展可有效地解决经济发展和生态环境间日益增长的矛盾。氢燃料汽车将处于氢能产业体系中核心地位&#xff0c;加快对氢燃料电池车的技术研发&#xff0c;大范围提高氢能源利用率&#xff0c;对于全世界形成以低碳排放为特征的工业体系具有重要意义。在…

【数据库】忘记mysql本地密码

目录 说明 操作步骤操作失败解决1.在以上操作步骤的第四步&#xff0c;输入mysql&#xff0c;报错第一种报错解决办法如下 第二种报错解决办法如下 2.从上面操作第二步后重新操作步骤如下报错解决办法如下 参考链接 说明 太久没使用本地mysql数据库&#xff0c;忘记了密码。 …

禅意工作-诗意生活

“禅意工作&#xff0c;诗意生活”能做到这两点&#xff0c;非常非常非常难。 AI的解释&#xff1a; “禅意工作&#xff0c;诗意生活”是一种追求内心平和与幸福的生活方式&#xff0c;它将工作与生活相结合&#xff0c;达到一种和谐的状态。以下是一些关于如何实现“禅意工…

GitHub快速上手--GitHub高效操作教程

一、前言 如果你正在看我的这篇文章&#xff0c;说明你已经对GitHub有了一些基础的了解&#xff0c;下面我们将详细叙述每一步的操作&#xff0c;以保证你能够快速上手GitHub&#xff0c;完成对代码的管理。 二、创建仓库 登录GitHub账号&#xff0c;点击页面右上角的加号&am…

flutter聊天界面-自定义表情键盘实现

flutter聊天界面-自定义表情键盘实现 flutter 是 Google推出并开源的移动应用开发框架&#xff0c;主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App&#xff0c;一套代码同时运行在 iOS 和 Android平台。 flutter开发基础腾讯IM的聊天应用&#xff0c;使用的是t…

PADS Layout中显示与布线标签页参数设置

1.“显示”标签页如图1 所示&#xff1a; 图1 显示标签页 显示标签页是用于去设置网络名以及管脚编号的字体大小的设置&#xff0c;建议是可以采取默认设置的&#xff0c;如果自己设计有另外要求&#xff0c;也是可以去进行设置。 2.“布线”标签也有三个子标签&#xff0c;首先…

基于matlab使用两个图像估计校准相机的姿势(附源码)

一、前言 运动结构 &#xff08;SfM&#xff09; 是从一组 3-D 图像估计场景的 2-D 结构的过程。此示例演示如何从两个图像估计校准相机的姿势&#xff0c;将场景的三维结构重建为未知比例因子&#xff0c;然后通过检测已知大小的对象来恢复实际比例因子。 此示例演示如何从使…

2.标识符、关键字、保留字

1、标识符 标识符&#xff1a;就是指开发人员为变量、属性、函数、参数取的名字 注意&#xff1a;标识符不能是关键字或保留字 JavaScript标识符 在JavaScript中&#xff0c;标识符&#xff08;Identifier&#xff09;是用于标识变量、函数、对象、属性或其他编程元素的名称。…

如何实现CesiumJS的视效升级?

CesiumJS作为一款强大的地理可视化引擎&#xff0c;为我们提供了丰富的地球数据可视化和交互展示的能力。然而&#xff0c;随着用户需求的不断增加和技术的不断进步&#xff0c;如何进一步提升CesiumJS的视觉效果成为了一个重要的问题。 首先&#xff0c;为了实现CesiumJS视觉…