随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

PKU 1151 Atlantis

题目链接:http://poj.org/problem?id=1151
/*
题意:
    给定n(n <= 100)个矩形,求它们的面积并。

解法:
离散化+线段树 或者 离散化+FloodFill

思路:
    数据量很小,直接把浮点数离散成整点,然后暴力FloodFill,最后统计
覆盖的块的实际面积。
    也可以采用线段树,具体解法如下面这题:
http://www.cppblog.com/menjitianya/archive/2011/03/29/142972.html
*/


#include 
<iostream>
#include 
<algorithm>
#include 
<vector>
#include 
<cmath>
using namespace std;

#define eps 1e-6
#define maxn 100000
// 垂直x轴的线段
struct VLine {
    
double x;
    
double y1, y2;  // y1 <= y2
    int val;        // in or out
    VLine() {}
    VLine(
double _x, double _y1, double _y2, int _v) {
        x 
= _x;
        y1 
= _y1;
        y2 
= _y2;
        val 
= _v;
    }

}
;
vector 
<VLine> Inc;
double tmp[maxn], bin[maxn];
int tmpsize, binsize;

bool cmp(VLine a, VLine b) {
    
return a.x < b.x;
}


void preBinaryProcess() {
    sort(tmp, tmp 
+ tmpsize);
    binsize 
= 0;
    bin[ 
++binsize ] = tmp[0];
    
int i;
    
for(i = 1; i < tmpsize; i++{
        
if(fabs(tmp[i] - tmp[i-1]) > eps)
            bin[ 
++binsize ] = tmp[i];
    }

}


int Binary(double val) {
    
int l = 1;
    
int r = binsize;
    
int m;
    
while(l <= r) {
        m 
= (l + r) >> 1;
        
if(fabs(val - bin[m]) < eps)
            
return m;
        
if(val > bin[m]) {
            l 
= m + 1;
        }
else
            r 
= m - 1;
    }


}


struct Tree {
    
int nCover;   // 当前线段被完全覆盖了几次
    double yLen;  // 测度、相邻扫描线间y方向的有效长度
    int l, r;     // 线段树该结点管理的区间
    int nowIndex; // 当前结点所在的数组下标

    
void Update() {
        
if(nCover > 0{
            yLen 
= bin[r] - bin[l];
        }
else {
            
if(l + 1 == r)
                yLen 
= 0;
            
else {
                yLen 
= T[nowIndex<<1].yLen + T[nowIndex<<1|1].yLen;
            }

        }

    }


    
int GetMid() {
        
return (l + r) >> 1;
    }

}
T[maxn*4];

void Build(int p, int l, int r) {
    T[p].nCover 
= T[p].yLen = 0;
    T[p].l 
= l; T[p].r = r;
    T[p].nowIndex 
= p;
    
if(l == r || l + 1 == r)
        
return ;
    
int mid = (l + r) >> 1;
    Build(p
<<1, l, mid);
    Build(p
<<1|1, mid, r);
}



void Insert(int p, int l, int r, int val) {

    
if(l <= T[p].l && T[p].r <= r) {
        T[p].nCover 
+= val;
        T[p].Update();
        
return ;
    }


    
int mid = T[p].GetMid();
    
if(l < mid) {
        Insert(p
<<1, l, r, val);
    }

    
if(r > mid) {
        Insert(p
<<1|1, l, r, val);
    }

    T[p].Update();
}


int n;
int main() {
    
int i;
    
int Case = 1;
    
while(scanf("%d"&n) != EOF && n) {
        Inc.clear();
        tmpsize 
= binsize = 0;
        
for(i = 0; i < n; i++{
            
double x1, y1, x2, y2;
            scanf(
"%lf %lf %lf %lf"&x1, &y1, &x2, &y2);
            Inc.push_back(VLine(x1, y1, y2, 
1));
            Inc.push_back(VLine(x2, y1, y2, 
-1));
            tmp[ tmpsize
++ ] = y1;
            tmp[ tmpsize
++ ] = y2;
        }

        sort(Inc.begin(), Inc.end(), cmp);
        preBinaryProcess();
        Build(
11, binsize);

        
double ans = 0;
        
for(i = 0; i < Inc.size(); i++{
            
int y1 = Binary(Inc[i].y1);
            
int y2 = Binary(Inc[i].y2);
            
if(y1 == y2)
                
continue;
            
if(i)
                ans 
+= (Inc[i].x - Inc[i-1].x) * T[1].yLen;
            Insert(
1, y1, y2, Inc[i].val);
        }

        printf(
"Test case #%d\nTotal explored area: %.2lf\n\n", Case++, ans);
    }

    
return 0;
}

posted on 2011-03-30 00:44 英雄哪里出来 阅读(1250) 评论(0)  编辑 收藏 引用 所属分类: 线段树


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理