淺談掃描線算法的應用


淺談掃描線算法的應用


關於掃描線

掃描線嚴格來說是一種思想(說了等於沒說系列

本蒟蒻在看其他人博客的時候學的一臉蒙蔽,在刷了幾道題目之后才略有感觸

掃描線可以理解為在處理二維平面時將平面分割為數條平行線段,再通過數據結構動態維護各線段求解一類平面問題(包括不限於矩形面積的交並)

基本方法是將平行於坐標軸的矩形(博主能力有限只能處理到這種程度)分解為(看作)數條與y軸平行的線段,再以x軸為基准將掃描線緩慢向右推進,每推進一步更新線段左右端點。

通常結合離散化食用

直接上題目吧QwQ,結合題目分析掃描線應用


各位期待已久(並沒有)的例題

洛谷P2061

題目概述:有一些矩形,底在x軸上,給出左右端點和高度,彼此之間可能有重疊部分,求輪廓覆蓋的總面積(求矩形面積並)

分析:

  首先離散化大家都懂,將x軸和y軸全部離散,再開一個數組記錄離散后大小對應的真實大小,這里還是貼一下離散的代碼防止后面有不理解的變量

  

    n=read(); for(int x,y,h,i=1;i<=n;++i) { x=read(),y=read();h=read(); e[++tot].x=x; e[tot].h=h; e[tot].id=i; e[++tot].x=y; e[tot].h=h; e[tot].id=i; } e[0].x=e[0].h=-1e9+7;//防止有 0 存在 
    sort(e+1,e+tot+1,cmq);//x軸離散 
    for(int i=1;i<=tot;++i) { ++totx; dis[totx]=e[i].x; int now=e[i].id; a[now].x==0?a[now].x=totx:a[now].y=totx; } sort(e+1,e+tot+1,cmp);//y軸離散 
    for(int i=1;i<=tot;++i) { if(e[i].h^e[i-1].h) { ++toty; up[toty]=e[i].h; } int now=e[i].id; a[now].h=toty; } e[0].h=0;

    下一步,我們需要將每條線段插入合適的地方,這里可以用到差分的思想,我們將每條線段對應的左端點在對應x軸位置上打上一個標記,掃描線遇到這個標記就將其插入數據結構中,在右端點再打上另一個標記,掃描線遇到就將線段刪除,這里可以用vector數組實現

for(int i=1;i<=n;++i) { int l=a[i].x; int r=a[i].y; ad[l].push_back(i);//插入 標記 
        cd[r].push_back(i);//刪除 標記 
    }

  接下來就是掃描線推進的過程了,其實只要一個循環模擬就夠了,每次利用線段樹維護線段左右端點,由於本題目下端點一律是x軸,所以只要維護上端點就夠了

    for(int i=1;i<=totx;++i) { int sum=cd[i].size(); for(int k=0;k<sum;++k)// 檢查 刪除 標記 
 { int now=cd[i][k]; update(1,toty,1,a[now].h,-1);//-1 刪除 線段 
 } sum=ad[i].size(); for(int k=0;k<sum;++k)// 檢查 插入 標記 
 { int now=ad[i][k]; update(1,toty,1,a[now].h,1); // 1 插入 線段 
 } int len=query(1,toty,1); if(dis[i+1]-dis[i]>=0) res+=(dis[i+1]-dis[i])*up[len];// 計算 答案 
 } printf("%lld\n",res);

  關於線段樹的維護方法:

    我們以y軸坐標為葉子結點,建立一顆權值線段樹,每次更新將對應節點數組+1,在區間中,>0表示該節點當前被線段覆蓋,==0表示該節點目前沒有線段

    再根據線段樹二分的特性,每次我們只要找到最右邊有數字的葉子節點,就可以知道矩形上端點在哪里了

    更新操作與一般線段樹相同就不放了,這里放下查詢

    

inline int query(int l,int r,int p) { if(l==r) return ans[p]?l:0;//注意 特判 0 !!! 
    int mid=(l+r)>>1; if(ans[rs(p)]) return query(mid+1,r,rs(p)); else 
        return query(l,mid,ls(p)); }

 

  這樣矩形面積的交基本結束QwQ 求並的方法類似,只要記錄區間線段覆蓋最大值就可以找到左右端點QwQ

有什么意見或者覺得博客有什么不足的地方歡迎各位留言,如果收到留言我會很高興的(假裝這里有一個高興的表情)

博客根據作者能力不定期更新,也許下次再見就更豐富了呢

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM