zoukankan      html  css  js  c++  java
  • 扫描线模版

    求解矩形面积交:

    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
    ",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
    ",ans);
        return 0;
    }

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

  • 相关阅读:
    秋叶收藏集, LC个人竞赛题目解析
    字典树,前缀树的模板!秒懂
    106. 从中序与后序遍历序列构造二叉树
    c++ enum 的枚举
    c++变量的声明和定义
    leetcode 39 组合总数(回溯)
    python lambda表达式应用
    python解压可迭代对象赋值给多个变量
    python之解压序列并赋值给变量
    Python循环列表的方法
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/13398603.html
Copyright © 2011-2022 走看看