線段樹與掃描線 —— 詳解算法思想及其C++實現

目錄

一、線段樹(Segment Tree)

基本概念

結構

操作

示例代碼

二、掃描線(Sweep Line)

基本概念

應用場景

示例代碼(矩形面積并集)

三、總結


一、線段樹(Segment Tree)

基本概念

????????線段樹是一種用于處理區間查詢和更新操作的數據結構,常用于解決區間最值、區間和等問題。它將一個區間劃分為若干個子區間,每個子區間對應樹中的一個節點。

結構

  • 葉子節點:代表數組中的單個元素。

  • 內部節點:代表數組中的某個區間,通常是其子節點的并集。

操作

  1. 構建(Build):從數組構建線段樹,時間復雜度為?O(n)O(n)。

  2. 查詢(Query):查詢某個區間的信息(如最小值、最大值、和等),時間復雜度為?O(log?n)O(logn)。

  3. 更新(Update):更新數組中的某個元素,并相應地更新線段樹,時間復雜度為?O(log?n)O(logn)。

示例代碼

#include <vector>  // 引入向量容器,用于動態數組
#include <algorithm>  // 引入算法庫,提供常用算法(如排序)class SegmentTree {
private:std::vector<int> tree;  // 線段樹的數組表示int n;  // 原始數組的大小// 構建線段樹的遞歸函數void build(const std::vector<int>& arr, int node, int start, int end) {if (start == end) {  // 如果當前區間只有一個元素tree[node] = arr[start];  // 直接將數組值賦給葉子節點} else {int mid = (start + end) / 2;  // 計算區間的中點build(arr, 2 * node + 1, start, mid);  // 遞歸構建左子樹build(arr, 2 * node + 2, mid + 1, end);  // 遞歸構建右子樹tree[node] = tree[2 * node + 1] + tree[2 * node + 2];  // 當前節點的值為左右子節點的和}}// 查詢區間和的遞歸函數int query(int node, int start, int end, int l, int r) {if (r < start || end < l) {  // 如果查詢區間與當前區間無交集return 0;  // 返回0,表示無貢獻}if (l <= start && end <= r) {  // 如果當前區間完全包含在查詢區間內return tree[node];  // 返回當前節點的值}int mid = (start + end) / 2;  // 計算區間的中點// 遞歸查詢左右子樹,并將結果相加return query(2 * node + 1, start, mid, l, r) + query(2 * node + 2, mid + 1, end, l, r);}// 更新數組中某個元素的遞歸函數void update(int node, int start, int end, int idx, int val) {if (start == end) {  // 如果當前區間只有一個元素tree[node] = val;  // 直接更新葉子節點的值} else {int mid = (start + end) / 2;  // 計算區間的中點if (idx <= mid) {  // 如果目標位置在左子樹update(2 * node + 1, start, mid, idx, val);  // 遞歸更新左子樹} else {  // 如果目標位置在右子樹update(2 * node + 2, mid + 1, end, idx, val);  // 遞歸更新右子樹}tree[node] = tree[2 * node + 1] + tree[2 * node + 2];  // 更新當前節點的值為左右子節點的和}}public:// 構造函數,初始化線段樹SegmentTree(const std::vector<int>& arr) {n = arr.size();  // 獲取原始數組的大小tree.resize(4 * n);  // 為線段樹分配空間,通常為4倍數組大小build(arr, 0, 0, n - 1);  // 構建線段樹}// 查詢區間和的公共接口int query(int l, int r) {return query(0, 0, n - 1, l, r);  // 調用私有查詢函數}// 更新數組中某個元素的公共接口void update(int idx, int val) {update(0, 0, n - 1, idx, val);  // 調用私有更新函數}
};

二、掃描線(Sweep Line)

基本概念

????????掃描線算法是一種用于處理幾何問題的算法,通常用于計算平面中多個矩形的并集面積、線段交點等問題。其核心思想是通過一條虛擬的線(通常是垂直于x軸或y軸的線)在平面上掃描,并在掃描過程中處理與線相交的幾何對象。

應用場景

  • 矩形面積并集:計算多個矩形的總面積。

  • 線段交點:找出所有線段的交點。

  • 多邊形面積:計算多邊形的面積。

示例代碼(矩形面積并集)

#include <vector>  // 引入向量容器,用于動態數組
#include <algorithm>  // 引入算法庫,提供常用算法(如排序)
#include <set>  // 引入集合容器,用于存儲和管理活動的區間// 定義事件結構體,表示矩形的開始或結束事件
struct Event {int x, y1, y2;  // x坐標,y1和y2表示矩形的垂直區間bool isStart;  // 標記事件是矩形的開始還是結束Event(int x, int y1, int y2, bool isStart) : x(x), y1(y1), y2(y2), isStart(isStart) {}
};// 比較函數,用于對事件按x坐標排序
bool compareEvents(const Event& a, const Event& b) {return a.x < b.x;  // 按x坐標升序排列
}// 計算矩形面積并集的函數
int calculateArea(const std::vector<std::vector<int>>& rectangles) {std::vector<Event> events;  // 存儲所有事件(矩形的開始和結束)for (const auto& rect : rectangles) {// 添加矩形的開始事件(左邊界)events.emplace_back(rect[0], rect[1], rect[3], true);// 添加矩形的結束事件(右邊界)events.emplace_back(rect[2], rect[1], rect[3], false);}// 對所有事件按x坐標排序std::sort(events.begin(), events.end(), compareEvents);std::multiset<std::pair<int, int>> activeIntervals;  // 存儲當前活動的垂直區間int prevX = 0;  // 前一個事件的x坐標int totalArea = 0;  // 總面積// 遍歷所有事件for (const auto& event : events) {int currentX = event.x;  // 當前事件的x坐標if (!activeIntervals.empty()) {  // 如果有活動的區間int height = 0;  // 當前掃描線覆蓋的總高度int prevY = -1;  // 前一個區間的y坐標// 遍歷所有活動區間,計算覆蓋的高度for (const auto& interval : activeIntervals) {if (prevY == -1) {  // 如果是第一個區間prevY = interval.first;  // 初始化prevY}if (interval.first > prevY) {  // 如果當前區間與前一個區間不重疊height += interval.first - prevY;  // 累加高度}prevY = std::max(prevY, interval.second);  // 更新prevY}// 計算當前掃描線與前一個掃描線之間的面積,并累加到總面積totalArea += height * (currentX - prevX);}prevX = currentX;  // 更新prevXif (event.isStart) {  // 如果是矩形的開始事件activeIntervals.insert({event.y1, event.y2});  // 將區間加入活動集合} else {  // 如果是矩形的結束事件activeIntervals.erase(activeIntervals.find({event.y1, event.y2}));  // 將區間從活動集合中移除}}return totalArea;  // 返回總面積
}

三、總結

  • 線段樹:適用于區間查詢和更新操作,常用于處理動態區間問題。

  • 掃描線:適用于處理幾何問題,特別是與平面中的矩形、線段等相關的問題。

????????這兩種算法思想在解決特定類型的問題時非常有效,理解它們的原理和應用場景有助于在編程競賽和實際開發中更好地解決問題。

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

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

相關文章

匯編代碼中嵌入回調函數的優化說明

一、概述 在 PowerPC 的匯編代碼中&#xff0c;我們需要實現調用 C 函數&#xff08;例如回調函數&#xff09;&#xff0c;并傳遞參數。本文將詳細介紹如何通過一系列步驟完成這一目標&#xff0c;包括代碼示例和詳細的注釋。 二、調用 C 函數的基本步驟及代碼 1. 保存工作寄…

Uni-App 雙欄聯動滾動組件開發詳解 (電梯導航)

本文基于提供的代碼實現一個左右聯動的滾動組件&#xff0c;以下是詳細的代碼解析與實現原理說明&#xff1a; <!--雙欄聯動滾動組件 - 技術解析功能特性&#xff1a;1. 左側導航欄與右側內容區雙向聯動2. 自適應容器高度3. 平滑滾動定位4. 動態內容位置計算 --> <te…

軟考復習-傳輸介質與編碼

傳輸介質 雙絞線 傳輸距離100一200m&#xff0c;即網線&#xff0c;有多種分類 UTP非屏蔽雙絞線 STP屏蔽雙絞線 線序標準有兩種為&#xff1a; T568A標準&#xff1a;綠白、綠、橙白、藍、藍白、橙、棕白、棕 T568B標準&#xff1a;橙白、橙、綠白、藍、藍白、綠、棕白、…

論文閱讀筆記:Denoising Diffusion Probabilistic Models (3)

論文閱讀筆記&#xff1a;Denoising Diffusion Probabilistic Models (1) 論文閱讀筆記&#xff1a;Denoising Diffusion Probabilistic Models (2) 論文閱讀筆記&#xff1a;Denoising Diffusion Probabilistic Models (3) 4、損失函數逐項分析 可以看出 L L L總共分為了3項…

PyTorch 面試題及參考答案(精選100道)

目錄 PyTorch 的動態計算圖與 TensorFlow 的靜態計算圖有何區別?動態圖的優勢是什么? 解釋張量(Tensor)與 NumPy 數組的異同,為何 PyTorch 選擇張量作為核心數據結構? 什么是 torch.autograd 模塊?它在反向傳播中的作用是什么? 如何理解 PyTorch 中的 nn.Module 類?…

#C8# UVM中的factory機制 #S8.1.4# 約束的重載

今天,復習一下《UVM實戰》一書中的 關于約束的重載 章節學習。 一 問題引導 文件:src/ch8/section8.1/8.1.2/rand_mode/my_transaction.sv4 class my_transaction extends uvm_sequence_item; …17 constraint crc_err_cons{18 crc_err == 1b0;19 }20 const…

空調遙控器低功耗單片機方案

RAMSUN空調遙控器采用先進的32位低功耗單片機作為核心控制器&#xff0c;通過優化軟件算法和硬件設計&#xff0c;實現了空調遙控器的低功耗運行。單片機集成了多種功能模塊&#xff0c;包括紅外發射、按鍵掃描、電源管理等&#xff0c;有效降低了整體功耗。同時&#xff0c;該…

結構型——代理模式

結構型——代理模式 代理模式指的是通過創建一個代理來控制對原始對象的訪問。代理在客戶端與實際對象之間充當“中介” 特點 訪問控制&#xff1a;代理對象可以控制對實際對象的訪問&#xff0c;從而實現對訪問權限的控制。延遲加載&#xff1a;代理對象可以在實際對象被調…

【算法】常見排序算法(插入排序、選擇排序、交換排序和歸并排序)

文章目錄 前言一、排序概念及常見排序算法框圖1.排序概念2.常見排序算法框圖 二、實現比較排序算法1.插入排序1.1 直接插入排序1.2 希爾排序 2.選擇排序2.1 直接選擇排序2.2 堆排序 3.交換排序3.1 冒泡排序3.2 快速排序3.2.1 hoare版本3.2.2 挖坑法3.2.3 lomuto前后指針 3.3 快…

Go語言分布式鎖實戰:dlock助力構建高并發穩定系統

在構建分布式系統時&#xff0c;一個常見且棘手的問題便是資源競爭和數據一致性問題。分布式鎖作為一種常用的解決方案&#xff0c;在多個進程或節點之間協調訪問共享資源時顯得尤為重要。今天&#xff0c;我們將介紹一款分布式鎖庫——dlock&#xff0c;并通過詳細的使用示例帶…

算法方法快速回顧

&#xff08;待修改&#xff09; 目錄 1. 雙指針2. 滑動窗口理論基礎 3. 二分查找3. 二分查找理論基礎 4. KMP5. 回溯算法6. 貪心算法7. 動態規劃7.1. 01背包7.2. 完全背包7.3. 多重背包 8. 單調棧9. 并查集10. 圖論10.1. 廣度優先搜索&#xff08;BFS&#xff09;10.2. 深度優…

深度學習:讓機器學會“思考”的魔法

文章目錄 引言&#xff1a;從“鸚鵡學舌”到“舉一反三”一、深度學習是什么&#xff1f;1. 定義&#xff1a;機器的“大腦”2. 核心思想&#xff1a;從數據中“悟”出規律 二、深度學習的“大腦”結構&#xff1a;神經網絡1. 神經元&#xff1a;深度學習的基本單元2. 神經網絡…

電動自行車/電動工具鋰電池PCM方案--SH367003、SH367004、SH79F329

在消費電子系統中&#xff0c;如手機電池包&#xff0c;筆記本電腦電池包等&#xff0c;帶有控制IC、功率MOSFETFE管以及其他電子元件的電路系統稱為電池充放電保護板Protection Circuit Module &#xff08;PCM&#xff09;&#xff0c;而對于動力電池的電池管理系統&#xff…

補碼詳細分析

補碼引入 舉一個生活化的例子 假設由一個掛鐘&#xff0c;它只能順時鐘調時間&#xff0c;那么它調時間就分成了一下兩種情況 正好順時針調就能調好 如&#xff1a;時針從5調到9需要逆時針調才能調好 如&#xff1a;時針從10調到7 在上面的情況中1是不用處理的&#xff0c;2…

計算機網絡入門:物理層與數據鏈路層詳解

&#x1f310; &#xff08;專業解析 中學生也能懂&#xff01;&#xff09; &#x1f4d6; 前言 計算機網絡就像數字世界的“高速公路系統”&#xff0c;而物理層和數據鏈路層是這條公路的基石。本文用 專業視角 和 生活化比喻 &#xff0c;帶你輕松理解這兩層的核心原理&a…

哪些視頻格式在webview2中播放可以設置成透明的?

在WebView2中&#xff0c;能夠播放并設置成透明背景的視頻格式主要取決于其支持的編解碼器以及視頻是否包含alpha通道&#xff08;透明度信息&#xff09;。以下是支持透明背景的視頻格式&#xff1a; 支持透明背景的視頻格式 1. WebM&#xff08;使用VP9編解碼器&#xff09; …

【基于ROS的A*算法實現路徑規劃】A* | ROS | 路徑規劃 | Python

### 記錄一下使用Python實現ROS平臺A*算法路徑規劃 ### 代碼可自取 &#xff1a;Xz/little_projecthttps://gitee.com/Xz_zh/little_project.git 目錄 一、思路分析 二、算法實現 三、路徑規劃實現 一、思路分析 要求使用A*算法實現路徑規劃&#xff0c;可以將該任務分為三…

2025-03-23 吳恩達機器學習3——多維特征

文章目錄 1 多元引入2 矢量化2.1 示例2.2 非矢量化實現2.3 矢量化實現2.4 應用 3 特征縮放3.1 舉例3.2 必要性3.3 方法3.3.1 最大最小值縮放&#xff08;Min-Max Scaling&#xff09;3.3.2 均值歸一化&#xff08;Mean Normalization&#xff09;3.3.3 Z 分數歸一化&#xff08…

正點原子內存管理學習和修改

由于項目需要用到內存管理進行動態申請和釋放&#xff0c;今天又重新學習了一下正點原子的內存管理實驗&#xff0c;溫習了一下內存管理的實質。首先先上正點原子內存管理的源代碼&#xff1a; malloc.c文件&#xff1a; #include "./MALLOC/malloc.h"#if !(__ARMC…

時空觀測者:俯身拾貝

目錄 中華文明時空貝殼集&#xff08;按時間排序&#xff09;1. 良渚玉琮&#xff08;約公元前3300-2300年&#xff09;2. 三星堆青銅神樹&#xff08;公元前1200年&#xff09;3. 殷墟甲骨文&#xff08;約公元前14世紀&#xff09;4. 京杭大運河&#xff08;公元前486年始建&…