ACM 扫描线

今天两个小时学会了扫描线,没有在网上找到比较清晰的教程,虽然我学会了,但是我也没有信心写出一篇清晰的教程。
如果屏幕前的你也在学习扫描线的话,给你几个我在学习扫描线过程中的难点。(写的过于潦草,几乎是只给自己看的,如果看不明白请立刻去看其他博客,不要在我的漏洞百出的东西上浪费时间)

非常建议各位在学习扫描线之前用线段树把这题写出来:
https://www.luogu.com.cn/problem/P3114
写出了这题 就可以不用看题解自己写出扫描线的代码了

用扫描线计算面积并:
由于并起来的图形过于复杂,我们将其分隔;有一种好的分隔方法是,用每个矩形的垂直的边所在的直线将整个图形进行分隔,总共有 2 n 2n 2n条边,将图形分隔为 2 n − 1 2n-1 2n1个矩形。
只需要计算出每个矩形的面积然后求和即可
每个矩形的宽就是相邻的两个矩形线段的差值
而其高难以计算,因为其高是有很多东西复合而成的。
但是我们可以将其描述为,从左向右看重叠的线段最终符合的内容。

可能存在的疑惑点:
一、如果有线段的 x x x轴坐标相同,也就是在一个区间内不只有一个矩形怎么办?
解答:请认真推算一遍代码,其中包含的 a n s = t r e e [ 1 ] ∗ ( l i n e [ i + 1 ] − l i n e [ i ] ) ans = tree[1] * (line[i + 1] -line[i]) ans=tree[1](line[i+1]line[i])如果两个相同,则差值为0,相当于只更新tree【1】
二、为什么不需要用到懒散标记?
解答:这个问题的关键在于,我们使用的是一个退化版的线段树,他在后面的进行change删除操作的时候,一定删除的是前面已经出现过的区间。因为矩形的入边和出边相等嘛。
最后是代码:

#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long
const int Mn = 1e5 + 1000;
struct line{
    
    
    ll x,y1,y2,falg;
    bool operator < (const line a){
    
    
        return x < a.x;
    }
}Line[Mn << 1];
ll y[Mn << 1],Y[Mn << 1];
struct {
    
    
    ll len;
    int flag;
}tree[Mn << 3];
int sz;
ll ans = 0;
inline void Up_data(int l,int r,int p){
    
    
    if(tree[p].flag) tree[p].len = y[r + 1] - y[l];
    else if(l == r) tree[p].len = 0;
    else tree[p].len = tree[p << 1].len + tree[p << 1 | 1].len;
}
void change(int ql,int qr,int l,int r,int p,int k){
    
    
    if(ql == l && qr == r){
    
    
        tree[p].flag += k;
        Up_data(l,r,p);
        return ;
    }
    int mid = (l + r) >> 1;
    if(qr <= mid) change(ql,qr,l,mid,p << 1,k);
    else
        if(ql > mid) change(ql,qr,mid + 1,r,p << 1 | 1,k);
    else {
    
    
        change(ql,mid,l,mid,p << 1,k);
        change(mid + 1,qr,mid + 1,r,p << 1 | 1,k);
    }
    Up_data(l,r,p);
}
int main()
{
    
    
    int n;scanf("%d",&n);
    ll x1,x2,y1,y2;
    for(int i = 1;i <= 2 * n;i += 2){
    
    
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        Line[i] = (line){
    
    x1,y1,y2,1};
        Line[i + 1] = (line){
    
    x2,y1,y2,-1};
    }
    n *= 2;
    sort(y + 1,y + 1 + n);sort(Line + 1,Line + 1 + n);
    sz = unique(y + 1,y + 1 + n) - y - 1;
    for(int i = 1;i < n;i ++){
    
    
        ll l,r;l = Line[i].y1;r = Line[i].y2;
        l = lower_bound(y + 1,y + 1 + sz,l) - y;
        r = lower_bound(y + 1,y + 1 + sz,r) - y - 1;
        change(l,r,1,sz,1,Line[i].falg);
        ans += tree[1].len * (Line[i + 1].x - Line[i].x);
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45673816/article/details/113826400