日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

扫描线讲解

發(fā)布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 扫描线讲解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

參考文章:
線段樹+掃描線(有關(guān)掃描線的理解)
線段樹+掃描線(基本原理)
掃描線
第二個文章里面的圖很生動:

我總結(jié)一下就是:將所給圖形的橫坐標(biāo)全部記錄,縱坐標(biāo)記錄為掃描線

然后對與兩個掃描線之間,找到最長的底邊,累計求面積

為了快速計算出截線段長度,可以將橫邊賦上不同的權(quán)值,具體為:對于一個矩形,其下邊權(quán)值為1,上邊權(quán)值為-1。也就是區(qū)間大于1的為連續(xù)的線段(圖中黃色部分)

我這里只是草草記錄,詳細(xì)過程可以看第三個講課博客

代碼:

#include <stdio.h> #include <iostream> #include <algorithm> #define lson (x << 1) #define rson (x << 1 | 1) using namespace std; const int MAXN = 1e6 + 10; typedef long long ll;int n, cnt = 0; ll x1, y1, x2, y2, X[MAXN << 1];struct ScanLine {ll l, r, h;int mark; // mark用于保存權(quán)值 (1 / -1)bool operator < (const ScanLine &rhs) const {return h < rhs.h;} } line[MAXN << 1];struct SegTree {int l, r, sum;ll len; // sum: 被完全覆蓋的次數(shù); // len: 區(qū)間內(nèi)被截的長度。 } tree[MAXN << 2];void build_tree(int x, int l, int r) { // 我覺得最不容易寫錯的一種建樹方法tree[x].l = l, tree[x].r = r;tree[x].len = 0;tree[x].sum = 0;if(l == r)return;int mid = (l + r) >> 1;build_tree(lson, l, mid);build_tree(rson, mid + 1, r);return; }void pushup(int x) {int l = tree[x].l, r = tree[x].r;if(tree[x].sum )/* 也就是說被覆蓋過 */ tree[x].len = X[r + 1] - X[l]; // 更新長度 elsetree[x].len = tree[lson].len + tree[rson].len; // 合并兒子信息 }void edit_tree(int x, ll L, ll R, int c) {int l = tree[x].l, r = tree[x].r; // 注意,l、r和L、R的意義完全不同 // l、r表示這個節(jié)點管轄的下標(biāo)范圍 // 而L、R則表示需要修改的真實區(qū)間if(X[r + 1] <= L || R <= X[l])return; // 這里加等號的原因: // 假設(shè)現(xiàn)在考慮 [2,5], [5,8] 兩條線段,要修改 [1,5] 區(qū)間的sum // 很明顯,雖然5在這個區(qū)間內(nèi),[5,8] 卻并不是我們希望修改的線段 // 所以總結(jié)一下,就加上了等號if(L <= X[l] && X[r + 1] <= R) {tree[x].sum += c;pushup(x);return;}edit_tree(lson, L, R, c);edit_tree(rson, L, R, c);pushup(x); }int main() {scanf("%d", &n);for(int i = 1; i <= n; i++) {scanf("%lli %lli %lli %lli", &x1, &y1, &x2, &y2);X[2 * i - 1] = x1, X[2 * i] = x2;line[2 * i - 1] = (ScanLine) {x1, x2, y1, 1};line[2 * i] = (ScanLine) {x1, x2, y2, -1}; // 一條線段含兩個端點,一個矩形的上下邊都需要掃描線掃過}n <<= 1; // 直接把 n <<= 1 方便操作sort(line + 1, line + n + 1);sort(X + 1, X + n + 1);int tot = unique(X + 1, X + n + 1) - X - 1; // 去重最簡單的方法:使用unique!(在<algorithm>庫中)build_tree(1, 1, tot - 1); // 為什么是 tot - 1 : // 因為右端點的對應(yīng)關(guān)系已經(jīng)被篡改了嘛… // [1, tot - 1]描述的就是[X[1], X[tot]]ll ans = 0;for(int i = 1; i < n ; i++) {/* 最后一條邊是不用管的 */edit_tree(1, line[i].l, line[i].r, line[i].mark); // 先把掃描線信息導(dǎo)入線段樹ans += tree[1].len * (line[i + 1].h - line[i].h); // 然后統(tǒng)計面積}printf("%lli", ans);return 0; }

總結(jié)

以上是生活随笔為你收集整理的扫描线讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。