zoukankan      html  css  js  c++  java
  • HDU 1542 Atlantis [离散化 + 扫描线 + 线段树]

    http://acm.hdu.edu.cn/showproblem.php?pid=1542
    给定平面上若干矩形,求出被这些矩形覆盖的区域的面积。

    对所有矩形的 y 坐标进行离散化,然后对所有竖线段按 x 坐标排序。标记矩形左边的线段是“入边”,右边的是“出边”。从左往右扫描。对于线段 li,只要知道当前所有竖线段的长度并 H,则 li1li 区间的面积就是 H×(xixi1) ,将其加到答案中。
    要高效的维护区间信息,首先想到的是线段树。然后,如果该边是“入边”,则将此边加到线段树中,否则,线段树中一定维护着这条边对应的“入边”,将它删除掉。
    对于每一条“入边”,在遇到它所对应的“出边”之前,它都会影响着右边的面积,所有这些“入边”的并就是它们共同产生的影响。只要在下一条边加入之前统计出当前这部分的面积,那扫描完所有边后被这些矩形覆盖的面积就计算出来了。

    还有一个问题。普通的线段树都是顶点式的,而这里要的是坐标区间式的。这有两种方法解决,一种是改变结点的闭合方式,如左闭右开,结点[l,r) 表示线段 [l,r] 。我是改变结点的表示含义,结点i 表示第 i 段线段,如结点[1,1] 表示 [0,1] 线段,即结点 [l,r] 表示线段 [l1,r] 。其实它们都一样,只是写起来不同。

    #include<bits/stdc++.h>
    using  namespace std;
    const double eps = 1e-9;
    
    #define rep(i,f,t) for(int i = (f),_end = (t); i <= _end; ++i)
    #define clr(c,x) memset(c,x,sizeof(c));
    
    #define MID int mid = (L+R)>>1;
    #define CHD int lc = node<<1,rc = node<<1|1;
    
    
    struct Node{
        double x,y1,y2;
        int from,to;
        bool flag;
        Node(double xx,double yy1,double yy2,bool f)
            :x(xx),y1(yy1),y2(yy2),flag(f){}
        bool operator< (const Node &n2) const{ return x < n2.x; }
    };
    vector<double> vs;
    vector<Node> line;
    
    const int maxn = 202<<2;
    struct sgt{
        int cov[maxn];
        double len[maxn];
        void init(){
            clr(cov,0);
            clr(len,0);
        }
        void maintain(int node,int L,int R){
            if(cov[node]){
                len[node] = vs[R]-vs[L-1];
            }else if(L != R){
                CHD;
                len[node] = len[lc]+len[rc];
            }else{
                len[node] = 0;
            }
        }
        double query(){
            return len[1];
        }
        void update(int from,int to,int val,int node,int L,int R){
            if(from <= L && R <= to){
                cov[node] += val;
            }else{
                MID;CHD;
                if(from <= mid)update(from,to,val,lc,L,mid);
                if(to > mid) update(from,to,val,rc,mid+1,R);
            }
            maintain(node,L,R);
        }
    }tree;
    
    bool equ(double x,double y){
        return fabs(x-y)<eps;
    }
    bool cmp(double x,double y){
        if(equ(x,y))return false;
        return x < y;
    }
    void pre(){
        sort(vs.begin(),vs.end());
        vs.erase(unique(vs.begin(),vs.end(),equ),vs.end());
        rep(i,0,line.size()-1){
            line[i].from = lower_bound(vs.begin(),vs.end(),line[i].y1,cmp) - vs.begin();
            line[i].to = lower_bound(vs.begin(),vs.end(),line[i].y2,cmp) - vs.begin();
        }
        sort(line.begin(),line.end());
    }
    
    int main(){
        int n;
        int cas = 0;
        while(scanf("%d",&n), n){
            tree.init();
            line.clear();
            vs.clear();
            rep(i,1,n){
                double x1,y1,x2,y2;
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                vs.push_back(y1);
                vs.push_back(y2);
                line.push_back(Node(x1,y1,y2,true));
                line.push_back(Node(x2,y1,y2,false));
            }
            pre();
            double x = 0;
            double ans = 0;
            rep(i,0,line.size()-1){
                double len = line[i].x-x;
                ans += len*tree.query();
                x = line[i].x;
                int v = (line[i].flag?1:-1);
                tree.update(line[i].from+1,line[i].to,v,1,1,line.size()-1);
            }
            printf("Test case #%d
    ",++cas);
            printf("Total explored area: %.2lf
    
    ",ans);
        }
        return 0;
    }

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    华为交换机中hybrid、access、trunk的区别
    debug调试
    网络基础--ICMP
    HCNA---ARP协议
    Python之字典
    python之元组
    网络基础--Telnet、SSH、FTP
    学习Cisco切换为华为的第一天---Telnet
    学思科,考华为,用华三。这是多少人的现况,快来听听我的经历~
    [P3385]【模板】负环 (spfa / bellman-ford)
  • 原文地址:https://www.cnblogs.com/DSChan/p/4861976.html
Copyright © 2011-2022 走看看