[模板]扫描线

[模板]扫描线求面积并

题目概述

给定矩形信息(以左下、右上顶点坐标为例),求矩形总覆盖面积

算法概述
  • 将给定的其中一维坐标离散化, 以此维所有坐标为断点将整个图形分割为若干小矩形(以x维为例)

  • 模拟一条扫描线扫过整个图形的过程,某一时刻扫描线覆盖到的线段长度为小矩形的一条边长,另一条边长则为未离散的一维的相邻坐标差(以y维为例)

  • 使用线段树维护某一时刻扫描线覆盖的区间长度:将(与扫描线)靠近扫描起点的矩形边权(以下边为例)值赋为1,对边为-1,则tre[1].len则为此时扫描线覆盖的线段长

注意事项
  • 线段树的lr并非实际区间边界而是离散化后的点编号,每个点编号x代表点x到点x + 1之间的线段,故实际边界为[a[l],a[r + 1]]

  • 对于每个矩形有两个点信息和边信息需要储存,故储存点信息的数组大小和储存边信息的结构体数组大小都为n << 1

  • 在对叶子节点执行pushup操作时会访问rt << 1rt << 1 | 1,故线段树数组大小为n << 4(普通线段树为n << 2,矩形点和边信息为n << 1,叶子节点pushupn << 1,结合为n << 4)

代码
#include <iostream>
#include <algorithm>
#define ll long long

using namespace std;

struct Lines{
    int l, r, h, key;
    bool operator < (const Lines &a) const{
        return h < a.h;
    }
}lne[2000010];
struct Trees{
    int l, r, sum;
    ll len;
}tre[1600010];
int n, a[1000010];

void pushup(int rt){
    int l = tre[rt].l, r = tre[rt].r;
    if(tre[rt].sum)
        tre[rt].len = a[r + 1] - a[l];
    else
        tre[rt].len = tre[rt << 1].len + tre[rt << 1 | 1].len;
}
void build(int rt, int l, int r){
    tre[rt].l = l, tre[rt].r = r, tre[rt].len = tre[rt].sum = 0;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(rt << 1, l, mid),  build(rt << 1 | 1, mid + 1, r);
}
void edit(int rt, ll x, ll y, int z){
    int l = tre[rt].l, r = tre[rt].r, mid = (l + r) >> 1;
    if(a[r + 1] <= x || y <= a[l]) return;
    if(x <= a[l] && y >= a[r + 1]){
        tre[rt].sum += z, pushup(rt);
        return;
    }
    if(x < a[mid + 1]) edit(rt << 1, x, y, z);
    if(y > a[mid + 1]) edit(rt << 1 | 1, x, y, z);
    pushup(rt);
}

int main(){
    cin >> n;
    int x1, x2, y1, y2;
    for(int i = 1; i <= n; i++){
        cin >> x1 >> y1 >> x2 >> y2;
        a[2 * i - 1] = x1, a[2 * i] = x2;
        lne[2 * i - 1] = (Lines) {x1, x2, y1, 1};
        lne[2 * i] = (Lines) {x1, x2, y2, -1};
    }
    n <<= 1;
    sort(lne + 1, lne + n + 1), sort(a + 1, a + n + 1);
    int m = unique(a + 1, a + n + 1) - a - 1;
    build(1, 1, m - 1);
    ll ans = 0;
    for(int i = 1; i <= n - 1; i++){
        edit(1, lne[i].l, lne[i].r, lne[i].key);
        ans += tre[1].len * (ll)(lne[i + 1].h - lne[i].h);
    }
    cout << ans << endl;
    return 0;
}
posted @ 2022-04-11 22:26  skyliyu  阅读(29)  评论(0编辑  收藏  举报