zoukankan      html  css  js  c++  java
  • 扫面线模板

    扫描线

    原理比较易懂

    参考:

    [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 ----
  • 相关阅读:
    【CITE】当类库项目中无法使用Application.StartupPath的时侯 (注:主要是在进行反射读取文件的时候!!)
    设置pictureBox的边框颜色
    怎么在Form1调用Form2中的成员?
    【CITE】DrawImage方法详解(转)
    Python-正则表达式实现计算器功能
    Python-面向对象进阶
    Python基础-封装与扩展、静态方法和类方法
    Python基础-接口与归一化设计、抽象类、继承顺序、子类调用父类,多态与多态性
    Python基础-继承与派生
    Python基础-月考
  • 原文地址:https://www.cnblogs.com/popodynasty/p/13950717.html
Copyright © 2011-2022 走看看