扫面线模板

扫描线

原理比较易懂

参考:

[1] 一文读懂扫描线算法

面积并

面积并只需要选择x或y其一做扫描线.每次扫描更新线段树,将扫描线长度 * 两次扫描线距离得到子矩形面积,累加统计答案.

/* 扫描线算法 */
/*
 * 前置知识: 线段树,离散化
 * 矩形面积并
 */

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 1e5+5;
struct SL{
    ll x;
    ll up,down;
    int kind;
    SL(){};
    SL(ll x,ll up,ll down,int kind)
        :x(x),up(up),down(down),kind(kind){}
    bool operator <(const SL&m)const{
        return x < m.x;
    }
};
SL line[N<<1];
int cover[N<<3]; // cover[i]表示区间[l,r]的全部结点都被覆盖了cover[i]次; cover[i] >= 0
ll tree[N<<3];   
// 通常我们建立N<<2的线段树,但是对于扫描线建树,n个矩形会构造出2n条扫描线,因此需要2N<<2即N<<3的空间
// tree[i] 表示[l,r]区间被覆盖的总长度

int len = 0;
ll discret[N<<1];

void push_up(int l,int r,int rt){
    if(cover[rt]){
        tree[rt] = discret[r]-discret[l];
    }else{
        if(l+1==r){ // 到达了叶结点,而叶结点的cover为0,说明这个叶结点没被扫描线覆盖
            tree[rt] = 0;
        }else{
            tree[rt] = tree[rt<<1] + tree[rt<<1|1];
        }
    }
}

void update(int l,int r,int rt,int ul,int ur,int degree){
    if(ul <= l && ur >= r){
        cover[rt] += degree;
        push_up(l,r,rt);
    }else{
        if(l+1==r){ // 运行到这里,说明这是一个不需要更新的叶结点
            return;
        }
        int mid = l+r>>1;
        if(ul <= mid){
            update(l,mid,rt<<1,ul,ur,degree);
        }
        if(ur > mid){
            update(mid,r,rt<<1|1,ul,ur,degree);
        }
        push_up(l,r,rt);
    }
}


int main(){
    int n;
    ll xa,xb,ya,yb;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%lld%lld%lld%lld",&xa,&ya,&xb,&yb);
        line[++len] = SL(xa,yb,ya,1);
        discret[len] = ya;
        line[++len] = SL(xb,yb,ya,-1);
        discret[len] = yb;
    }

    sort(discret+1,discret+1+len);
    sort(line+1,line+1+len);
    int idlabels = unique(discret+1,discret+1+len)-(discret+1);

    ll ans = 0;
    for(int i = 1; i <= len; i++){
        ans += tree[1] * (line[i].x-line[i-1].x);
        int ul = lower_bound(discret+1,discret+1+idlabels,line[i].down)-discret;
        int ur = lower_bound(discret+1,discret+1+idlabels,line[i].up)-discret;
        update(1,idlabels,1,ul,ur,line[i].kind);
    }
    printf("%lld",ans);
    system("pause");
    return 0;
}

周长并

周长并需要在x,y方向做两次扫描线. 对于每次线段树的更新,记录扫描线长度的变化量的绝对值.累加统计答案.
注意求周长并,对于距离差值为0的多根扫描线,需要先计算入边,再计算出边.具体可以看这篇题解

#include <cstdio>
#include <algorithm>
using namespace std;
#define MIN(a,b) (a<b?a:b)
#define FABS(x) (x>0?x:-(x))
typedef long long ll;
const int N = 5000+5;


struct data{
    ll xa,xb,ya,yb;
};

struct SL{
    ll pos,upper,lower;
    int kind;
    SL(){};
    SL(ll a,ll b,ll c,int d):pos(a),upper(b),lower(c),kind(d){}
    bool operator<(const SL&m)const{
        if(pos != m.pos)
            return pos < m.pos;
        else return kind > m.kind;
    }
};
ll ans;
data arr[N];
int treeSize;
int slSize;
ll tree[N<<3];
ll cover[N<<3]; 
ll orderPos[N<<2];
SL line[N<<2];

void push_up(int left,int right,int rt){
    if(cover[rt]){
        tree[rt] = orderPos[right] - orderPos[left];
    }else{
        if(left+1==right){
            tree[rt] = 0;
        }else{
            tree[rt] = tree[rt<<1] + tree[rt<<1|1];
        }
    }
}

void build(int l,int r,int rt){
    tree[rt] = 0;
    cover[rt] = 0;
    if(l+1==r){
        return;
    }else{
        int mid = l+r>>1;
        build(l,mid,rt<<1);
        build(mid,r,rt<<1|1);
    }
}
void clear(){
    build(1,treeSize,1);
    treeSize = slSize = 0;
}

void update(int l,int r,int rt,int ul,int ur,int kind){
    if(ul <= l && ur >= r){
        cover[rt] += kind;
        push_up(l,r,rt);
    }else{
        int mid = l+r>>1;
        if(l+1==r){
            return;
        }
        if(ul <= mid){
            update(l,mid,rt<<1,ul,ur,kind);
        }
        if(ur > mid){
            update(mid,r,rt<<1|1,ul,ur,kind);
        }
        push_up(l,r,rt);
    }
}

void sweep(){
    sort(orderPos+1,orderPos+1+slSize);
    sort(line+1,line+1+slSize);
    treeSize = unique(orderPos+1,orderPos+1+slSize) - (orderPos+1);
    for(int i = 1; i <= slSize; i++){
        int temp = tree[1];
        int ul = lower_bound(orderPos+1,orderPos+1+treeSize,line[i].lower) - orderPos;
        int ur = lower_bound(orderPos+1,orderPos+1+treeSize,line[i].upper) - orderPos;
        update(1,treeSize,1,ul,ur,line[i].kind);
        ans += FABS(tree[1]-temp);
    }
}
int main(){

    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        data &p = arr[i];
        scanf("%lld%lld%lld%lld",&p.xa,&p.ya,&p.xb,&p.yb);
    }

    for(int i = 1; i <= n; i++){
        data &p = arr[i];
        orderPos[++slSize] = p.ya;
        line[slSize].pos = p.xa;
        line[slSize].lower = p.ya;
        line[slSize].upper = p.yb;
        line[slSize].kind = 1;

        orderPos[++slSize] = p.yb;
        line[slSize].pos = p.xb;
        line[slSize].lower = p.ya;
        line[slSize].upper = p.yb;
        line[slSize].kind = -1;
    }
    sweep();

    clear();

    for(int i = 1; i <= n; i++){
        data &p = arr[i];
        orderPos[++slSize] = p.xa;
        line[slSize].pos = p.ya;
        line[slSize].lower = p.xa;
        line[slSize].upper = p.xb;
        line[slSize].kind = 1;

        orderPos[++slSize] = p.xb;
        line[slSize].pos = p.yb;
        line[slSize].lower = p.xa;
        line[slSize].upper = p.xb;
        line[slSize].kind = -1;
    }
    sweep();

    printf("%lld",ans);
    // system("pause");
    return 0;
}
---- suffer now and live the rest of your life as a champion ----
原文地址:https://www.cnblogs.com/popodynasty/p/13950717.html