扫描线模版

求解矩形面积交:

https://www.luogu.com.cn/problem/P5490

 

为了和区间匹配: 线段树的[l,r] 实际上代表了区间 [l,r + 1]

#include <cstdio>
#include <iostream>
#include <algorithm>

#define ll long long
#define ull unsigned long long
#define ls nod<<1
#define rs (nod<<1)+1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define INF 0x3f3f3f3f
#define max(a, b) (a>b?a:b)
#define min(a, b) (a<b?a:b)


const double eps = 1e-8;
const int maxn = 1e6 + 10;
const ll MOD = 1e9 + 7;
const int mlog=20;

int sgn(double a) { return a < -eps ? -1 : a < eps ? 0 : 1; }

using namespace std;

ll x1,y1,x2,y2,X[maxn << 1];

struct ScanLine {
    ll l,r,h;
    int mark;

    bool operator < (const ScanLine &rhs) const {
        return h < rhs.h;
    }
} line[maxn << 2];

struct segment_tree {
    int l,r,sum;
    ll len;
}tree[maxn << 2];

void build(int l,int r,int nod) {
    tree[nod].l = l,tree[nod].r = r;
    tree[nod].len = 0;
    tree[nod].sum = 0;
    if (l == r)
        return ;
    int mid = (l + r) >> 1;
    build(l,mid,ls);
    build(mid+1,r,rs);
}

void push_up(int nod) {
    int l = tree[nod].l,r = tree[nod].r;
    if (tree[nod].sum) {
        tree[nod].len = X[r+1] - X[l];
    }
    else
        tree[nod].len = tree[ls].len + tree[rs].len;
}

void modify(ll x,ll y,int f,int nod) {
    int l = tree[nod].l,r = tree[nod].r;
    if (X[r+1] <= x || X[l] >= y)
        return ;
    if (X[l] >= x && X[r+1] <= y) {
        tree[nod].sum += f;
        push_up(nod);
        return ;
    }
    modify(x,y,f,ls);
    modify(x,y,f,rs);
    push_up(nod);
}

int main() {
    int n;
    scanf("%d",&n);
    for (int i = 1;i <= n;i++) {
        scanf("%lld%lld%lld%lld",&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;
    sort(line + 1,line + 1 + n);
    sort(X + 1,X + 1 + n);
    int tot = unique(X + 1,X + n + 1) - X - 1;
    build(1,tot-1,1);
    ll ans = 0;
    for (int i = 1;i < n;i++) {
        modify(line[i].l,line[i].r,line[i].mark,1);
        ans += tree[1].len * (line[i+1].h - line[i].h);
    }
    printf("%lld\n",ans);
    return 0;
}

 

求矩形的周长:

https://www.luogu.com.cn/problem/P1856

 

 

 

 

 

 

#include <cstdio>
#include <iostream>
#include <algorithm>

#define ll long long
#define ull unsigned long long
#define ls nod<<1
#define rs (nod<<1)+1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define INF 0x3f3f3f3f
#define max(a, b) (a>b?a:b)
#define min(a, b) (a<b?a:b)


const double eps = 1e-8;
const int maxn = 1e6 + 10;
const ll MOD = 1e9 + 7;
const int mlog=20;

int sgn(double a) { return a < -eps ? -1 : a < eps ? 0 : 1; }

using namespace std;

ll x1,y1,x2,y2,X[maxn << 1];

struct ScanLine {
    ll l,r,h;
    int mark;

    // 这里和面积交那里多了一个特判
    bool operator < (const ScanLine &rhs) const {
       if (h == rhs.h)
           return mark > rhs.mark;
       return h < rhs.h;
    }
} line[maxn << 2];

struct segment_tree {
    int l,r,sum,c;
    bool lc,rc;
    ll len;
}tree[maxn << 2];

void build(int l,int r,int nod) {
    tree[nod].l = l,tree[nod].r = r;
    tree[nod].lc = tree[nod].rc = false;
    tree[nod].len = 0;
    tree[nod].sum = 0;
    if (l == r)
        return ;
    int mid = (l + r) >> 1;
    build(l,mid,ls);
    build(mid+1,r,rs);
}

void push_up(int nod) {
    int l = tree[nod].l,r = tree[nod].r;
    if (tree[nod].sum) {
        tree[nod].len = X[r+1] - X[l];
        tree[nod].lc = tree[nod].rc = true;
        tree[nod].c = 1;
    }
    else {
        tree[nod].len = tree[ls].len + tree[rs].len;
        tree[nod].lc = tree[ls].lc,tree[nod].rc = tree[rs].rc;
        tree[nod].c = tree[ls].c + tree[rs].c;
        if (tree[ls].rc && tree[rs].lc)
            tree[nod].c -= 1;
    }
}

void modify(ll x,ll y,int f,int nod) {
    int l = tree[nod].l,r = tree[nod].r;
    if (X[r+1] <= x || X[l] >= y)
        return ;
    if (X[l] >= x && X[r+1] <= y) {
        tree[nod].sum += f;
        push_up(nod);
        return ;
    }
    modify(x,y,f,ls);
    modify(x,y,f,rs);
    push_up(nod);
}

int main() {
    int n;
    scanf("%d",&n);
    for (int i = 1;i <= n;i++) {
        scanf("%lld%lld%lld%lld",&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;
    sort(line + 1,line + 1 + n);
    sort(X + 1,X + 1 + n);
    int tot = unique(X + 1,X + n + 1) - X - 1;
    build(1,tot-1,1);
    ll ans = 0;
    ll pre = 0;
    for (int i = 1;i < n;i++) {
        modify(line[i].l,line[i].r,line[i].mark,1);
        ans += abs(pre - tree[1].len);
        pre = tree[1].len;
        ans += 2 * tree[1].c * (line[i + 1].h - line[i].h);
    }
    ans += line[n].r - line[n].l;
    printf("%lld\n",ans);
    return 0;
}

 

具体的讲解的博客:https://ncc79601.blog.luogu.org/scan-line

posted @ 2020-07-29 17:53  _Ackerman  阅读(243)  评论(0编辑  收藏  举报