【一維 前綴和+差分】

一、一維前綴和

1.1 定義

給定一個數組 a[1..n],其前綴和數組 pre[1..n] 定義為:

pre[i]=a[1]+a[2]+?+a[i] pre[i] = a[1] + a[2] + \dots + a[i] pre[i]=a[1]+a[2]+?+a[i]

pre[i] 表示原數組從第 1 項到第 i 項的和。

1.2 構建

int a[N], pre[N];
for (int i = 1; i <= n; i++) 
{pre[i] = pre[i - 1] + a[i];
}

1.3 區間求和

使用前綴和可以在 O(1)O(1)O(1) 時間內求任意區間 [l,r][l, r][l,r] 的和:

sum=pre[r]?pre[l?1] sum = pre[r] - pre[l - 1] sum=pre[r]?pre[l?1]

公式推導:

pre[r]=a[1]+a[2]+?+a[l?1]+a[l]+?+a[r]pre[l?1]=a[1]+a[2]+?+a[l?1] pre[r] = a[1] + a[2] + \dots + a[l-1] + a[l] + \dots + a[r] \\ pre[l-1] = a[1] + a[2] + \dots + a[l-1] pre[r]=a[1]+a[2]+?+a[l?1]+a[l]+?+a[r]pre[l?1]=a[1]+a[2]+?+a[l?1]

所以兩者一減,剛好剩下區間 [l,r][l, r][l,r] 的和。

1.4 應用場景

  • 快速計算區間和
  • 優化暴力 O(n2)O(n^2)O(n2) 的區間統計問題為 O(n)O(n)O(n)

1.5 示例

// 輸入一個數組,求多個區間 [l, r] 的和
int a[N], pre[N];
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + a[i];while (q--) 
{int l, r;cin >> l >> r;cout << pre[r] - pre[l - 1] << '\n';
}

二、一維差分數組

2.1 定義

對于原數組 a[1..n],其差分數組 diff[1..n] 定義為:

diff[i]=a[i]?a[i?1]??(i≥2),??diff[1]=a[1] diff[i] = a[i] - a[i - 1]\ \ (i \geq 2),\ \ diff[1] = a[1] diff[i]=a[i]?a[i?1]??(i2),??diff[1]=a[1]

2.2 構建

int a[N], diff[N];
diff[1] = a[1];
for (int i = 2; i <= n; i++) 
{diff[i] = a[i] - a[i - 1];
}

2.3 區間加法操作

若想對區間 [l,r][l, r][l,r] 所有數加上 ddd,只需:

diff[l] += d;
diff[r + 1] -= d;

原理在于:差分數組記錄的是“增量”,只需要在區間起點加一個數、在區間終點的下一位減去這個數,就能確保中間所有位置都累加這個值。

然后通過前綴和還原整個數組:

a[1] = diff[1];
for (int i = 2; i <= n; i++) 
{a[i] = a[i - 1] + diff[i];
}

2.4 區間減法操作

若想對區間 [l,r][l, r][l,r] 所有數減去 ddd,也可以使用差分數組:

diff[l] -= d;
diff[r + 1] += d;

原理類似:差分數組記錄的是“增量”,如果我們想對一個區間 [l,r][l, r][l,r] 的所有元素減去 ddd,只需要在區間起點加上 ?d-d?d,在區間終點的下一位加上 +d+d+d,就能確保整個區間內的值都減少 ddd,而其他位置不受影響。這與區間加法操作完全對稱,只是將 ddd 替換為 ?d-d?d


三、差分原理

3.1 目的

差分數組的核心目的是:將原本需要 O(n) 的區間修改操作優化為 O(1)

比如:我們想對數組中一段區間 [l,r][l, r][l,r] 的所有元素都加上一個數 ddd,若用原數組暴力加法,每次操作就要 O(r?l+1)O(r-l+1)O(r?l+1);當有 mmm 次操作時,總復雜度是 O(mn)O(mn)O(mn),會超時。

3.2 差分數組的構建

我們構建一個數組 diff[1…n]diff[1 \ldots n]diff[1n]

diff[i]=a[i]?a[i?1] diff[i] = a[i] - a[i - 1] diff[i]=a[i]?a[i?1]

也可以理解為:

差分數組記錄的是原數組中相鄰兩項之間的“變化量”。

根據這個定義,有:

a[i]=diff[1]+diff[2]+?+diff[i]?a[i]=∑j=1idiff[j] a[i] = diff[1] + diff[2] + \dots + diff[i] \Rightarrow a[i] = \sum_{j=1}^{i} diff[j] a[i]=diff[1]+diff[2]+?+diff[i]?a[i]=j=1i?diff[j]

也就是說,原數組可以通過差分數組做前綴和來還原

3.3 差分操作的核心邏輯

想要將區間 [l,r][l, r][l,r] 所有數都加上 ddd,我們可以在 diff[] 上做如下處理:

diff[l] += d;
diff[r + 1] -= d;
為什么這樣就能完成整個區間的加法?

我們回憶差分的“還原”過程:

a[1] = diff[1];
a[2] = a[1] + diff[2];
a[3] = a[2] + diff[3];
...

你會發現,前綴相加會讓 diff[l] 的影響一直傳導下去。直到 diff[r+1] 把這部分影響抵消為止。

也就是說:

  • a[l]a[l]a[l]a[r]a[r]a[r] 都被加上了 ddd
  • a[r+1]a[r+1]a[r+1] 之后的數不受影響

這就實現了:O(1) 修改一個區間


四、一個形象的類比

假設你站在樓梯上,從第 1 級樓梯往上走,a[i] 是你在第 i 級臺階上的高度。

  • 前綴和:相當于你每走一步都記一下總共走了多遠。
  • 差分數組:相當于你記錄每一步你上升(或下降)了多少。

你只要知道每一步的變化量(差分數組),就能還原出每一級臺階的實際高度(原數組);你也能知道在一段范圍內你升高了多少(前綴和)。



五、前綴和與差分的區別與聯系

類別作用技術本質時間復雜度
前綴和快速查詢區間和把每個位置存成前綴累加和查詢 O(1)O(1)O(1),構建 O(n)O(n)O(n)
差分數組快速區間修改存儲相鄰值之間的“變化”修改 O(1)O(1)O(1),恢復 O(n)O(n)O(n)

它們的關系就像:

  • 前綴和是累計的“總和”
  • 差分是相鄰的“變化量”

差分數組其實就是前綴和的逆操作。


六、常見問題匯總

  1. 差分數組的還原為什么用前綴和?

    差分數組記錄的是相鄰元素之間的增量,所以前綴和就是原數組。

  2. 差分數組是否支持區間乘法?

    不支持,差分只能處理區間加減。

  3. 差分數組是否可以從 0 開始?

    可以,但要注意下標對應的意義,最好從 1 開始更清晰。

  4. 是否每次都需要重建差分數組?

    看情況。如果每次操作互不干擾,可以復用;否則建議重建或靜態開數組并清空。


七、總結

  • 前綴和用于高效區間查詢
  • 差分數組用于高效區間修改
  • 兩者配合使用是處理“區間加減 + 查詢”類問題的利器

在處理數據量較大的題目(如 10510^510510610^6106)時,前綴和與差分是比線段樹更快、更簡潔的選擇。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91124.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91124.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91124.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot 雙數據源配置

文章目錄什么是雙數據源&#xff1f;為什么需要雙數據源&#xff1f;核心實現原理完整示例注意什么是雙數據源&#xff1f; 雙數據源是指在一個應用程序中同時配置和使用兩個不同的數據庫連接。比如&#xff1a; 一個連接訂單數據庫&#xff0c;處理業務數據一個連接用戶中心…

【Java】【力扣】102.二叉樹層序遍歷

思路一個輔助隊列&#xff08;初始化隊列&#xff1a;根節點入隊&#xff09;一個節點 出隊&#xff0c;他的左右孩子入隊循環 直到隊列為空舉例代碼public List<List<Integer>> levelOrder(TreeNode root) {if (rootnull){return new ArrayList<List<Intege…

為什么有些PDF無法復制文字?原理分析與解決方案

在日常辦公和學習中&#xff0c;我們經常會從PDF文件中復制文字&#xff0c;用于編輯、引用、整理筆記。但你是否也遇到過這樣的情況&#xff1a;有些PDF中的文字根本無法選中&#xff0c;更無法復制粘貼&#xff1f; 看起來像是“文字”&#xff0c;但操作上卻完全無效——這…

LabVIEW瀏覽器ActiveX事件交互

?程序圍繞 WebBrowser ActiveX 控件&#xff0c;借 “Reg Event Callback” 注冊標題變更回調&#xff0c;“Callback - Title Change.vi” 處理標題數據&#xff0c;“Monitor...” 響應 URL 變更&#xff0c;“Unregister...” 清理資源&#xff0c;實現瀏覽器事件交互與管控…

C++后端面試八股文

一、C 語言基礎與底層原理請解釋 new / delete 和 malloc / free 的區別和聯系&#xff0c;以及使用它們時需要注意什么new 和 delete 是C的??運算符&#xff08;Operator&#xff09;??。這意味著它們可以被類&#xff08;通過 operator new 和 operator delete&#xff0…

基礎分類模型及回歸簡介(一)

一、先搞懂兩個核心任務&#xff1a;分類和回歸咱們生活中總遇到要 “判斷” 或 “預測” 的事&#xff1a;比如看到一個水果&#xff0c;判斷是蘋果還是橘子 —— 這就是分類&#xff08;結果是 “類別”&#xff09;&#xff1b;比如根據西瓜的大小、顏色&#xff0c;猜它能賣…

【LeetCode 熱題 100】114. 二叉樹展開為鏈表——(解法二)分治

Problem: 114. 二叉樹展開為鏈表 給你二叉樹的根結點 root &#xff0c;請你將它展開為一個單鏈表&#xff1a; 展開后的單鏈表應該同樣使用 TreeNode &#xff0c;其中 right 子指針指向鏈表中下一個結點&#xff0c;而左子指針始終為 null 。 展開后的單鏈表應該與二叉樹 先序…

【WPF】WPF 自定義控件 實戰詳解,含命令實現

&#x1f9e9;《WPF 自定義控件》實戰詳解本文將圍繞如何編寫一個自定義控件&#xff08;如帶右鍵菜單的圖片控件 ImageView&#xff09;&#xff0c;逐步講解其定義、命令綁定與 ContextMenu 中常見的語法技巧。&#x1f9f1; 一、創建一個 WPF 自定義控件的步驟 WPF 中自定義…

Flink 2.0 DataStream算子全景

在實時流處理中&#xff0c;Apache Flink的DataStream API算子是構建流處理 pipeline 的基礎單元。本文基于Flink 2.0&#xff0c;聚焦算子的核心概念、分類及高級特性。 一、算子核心概念&#xff1a;流處理的"原子操作 1. 數據流拓撲&#xff08;Stream Topology&#x…

Flask 入門到實戰(2):使用 SQLAlchemy 打造可持久化的數據層

Flask 入門到實戰&#xff1a;使用 SQLAlchemy 打造可持久化的數據層一、前言&#xff1a;為什么用 Flask-SQLAlchemy&#xff1f; 在 Python Web 開發中&#xff0c;操作數據庫的方式主要有兩種&#xff1a; 直接寫 SQL&#xff08;繁瑣且難維護&#xff09;使用 ORM&#xff…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | GithubProfies(GitHub 個人資料)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— GithubProfies組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script setup…

simscape中坐標系和坐標變換Frames and Transforms

為了更便捷地描述單個物體的運動&#xff0c;最好以該物體的質心為坐標原點建立坐標系&#xff0c;從而可以非常方便地描述其旋轉運動。因此&#xff0c;在計算多個物體之間的位置關系時&#xff0c;為了計算方便&#xff0c;需要頻繁地更換坐標框架&#xff0c;這也是multibod…

構建分布式光伏“四可”能力:支撐新型電力系統安全穩定運行的關鍵路徑

隨著我國新能源裝機規模的跨越式增長&#xff0c;國家能源戰略對新能源電站的規范化接入與精細化調度管理提出了更高要求。在電力市場化改革深化與新型電力系統構建的關鍵時期&#xff0c;保障電網安全穩定、提升新能源高效消納能力已成為核心議題。國家能源局于2025年1月17日正…

UART寄存器介紹

在 STM32 微控制器中&#xff0c;UART&#xff08;通用異步收發傳輸器&#xff09;通信通過多個寄存器實現配置和數據傳輸。下面詳細解析 UART 的核心寄存器及其功能。1. 狀態寄存器&#xff08;USART_SR&#xff09;狀態寄存器反映 UART 當前的工作狀態&#xff0c;用于判斷數…

寫一個算法對一組值進行歸一化映射,使它們在視覺上有明顯的區分度,尤其在數據集分布不均時仍能體現差異

問題&#xff1a; 有一批數據&#xff0c;都是隨機值范圍是不確定&#xff0c;我需要用這個值來繪制同樣數量圓&#xff0c;不同值他們的圓半徑不同&#xff0c;考慮到數據有時候大小偏差不大&#xff0c;這1000個值有可能是集中在10,20之間&#xff0c;也可能是分布廣泛&#…

具身智能零碎知識點(五):VAE中對使用KL散度的理解

VAE中對使用KL散度的理解什么是 VAE (Variational AutoEncoder)&#xff1f;從自編碼器 (AE) 說起VAE&#xff1a;讓潛在空間變得“有意義”和“連續”KL 散度是如何用到的&#xff1f;通俗理解 KL 散度在 VAE 中的作用&#xff1a;帶來的好處&#xff1a;KL 散度公式 (無需背誦…

理解:進程、線程、協程

線程、進程和協程是并發編程的重要組成部分。進程&#xff08;Process&#xff09;定義進程是操作系統分配資源的基本單位&#xff0c;表示一個正在執行的程序。一旦一個程序被加載到內存中&#xff0c;它就成為一個進程&#xff0c;而每個進程都有其獨立的內存空間。特征進程之…

總結一下找素數的三種方法

目錄 一試除法 二埃氏篩 三線性篩(歐拉篩) 一試除法 思想&#xff1a;就是判斷某個數x是不是素數,就判斷從2開始到小于根號x的范圍內有沒有能夠取余不等于0的,這個說明當前值就是x的一個因子&#xff0c;所以不是素數。 代碼&#xff1a; import java.util.Scanner;public…

基于Yolov8車輛檢測及圖像處理系統【有代碼】

0 引言 隨著城市化進程的加速和機動車保有量的快速增長,交通管理、智能監控和自動駕駛等領域對車輛目標檢測技術的需求日益增長。車輛目標檢測是計算機視覺領域的一個重要研究方向,其目標是從圖像或視頻序列中準確識別和定位車輛,為后續的車輛跟蹤、行為分析和交通流量統計…

MySQL密碼管理器“mysql_config_editor“

目錄 核心能力 常用命令速查 為什么更安全&#xff1f; 典型場景 mysql_config_editor 是 MySQL 官方自帶的一款命令行小工具&#xff0c;作用一句話&#xff1a;把賬號、密碼、主機、端口等連接信息加密存起來&#xff0c;下次連接時只敲一個名字即可&#xff0c;不用再寫…