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

HDU 1255 覆盖的面积

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
/*
题意:
    给出N(N <= 1000)个矩形,求被覆盖2次以上的矩形面积并。

解法:
离散化+线段树

思路:
    类似于覆盖一次的矩形面积并问题,还是用线段树求解,首先我们
将每个矩形的纵向边投影到Y轴上,这样就可以把矩形的纵向边看成一个
闭区间,用线段树来维护这些矩形边的并。现在求的是矩形的面积并,
于是可以枚举矩形的x坐标,然后检测当前相邻x坐标上y方向的合法长度,
两者相乘就是其中一块面积,枚举完毕后就求得了所有矩形的面积并。
    我的线段树结点描述保存了以下信息:区间的左右端点、结点所在
数组编号(因为采用静态结点可以大大节省申请空间的时间)、该结点
被竖直线段完全覆盖的次数Cover和当前结点覆盖一次的y方向长度yOnce
和当前结点覆盖多次的y方向长度yMore。
    其实和矩形面积并的唯一差别就是在计算Cover后的Update函数,更
新yOnce和yMore的值,分情况讨论:
1. 当nCover>1时,yOnce = 0; yMore = 区间实际长度;
2. 当nCover=1时,yMore = 两棵子树的yOnce+yMore; 
                 yOnce = 区间实际长度 - yMore;
3. 当nCover=0时,如果是叶子结点 yOnce = 0; yMore = 0;
                 否则 
                 yOnce = 两棵子树的yOnce和;
                 yMore = 两棵子树的yMore和;
*/


#include 
<iostream>
#include 
<algorithm>
#include 
<vector>
#include 
<cmath>

using namespace std;

#define maxn 2200


double tmp[maxn], bin[maxn];
int tmpsize, size;


struct Tree {
    
int p;
    
int l, r;
    
int nCover;
    
double ylenOnce, ylenMore;

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

        }

    }

}
T[maxn*4];

struct VLine {
    
double x;
    
double y1, y2;
    
int val;
    VLine() 
{}
    VLine(
double _x, double _y1, double _y2, int _v) {
        x 
= _x;
        y1 
= _y1;
        y2 
= _y2;
        val 
= _v;
    }

}
;
vector 
< VLine > Vl;

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


void Process() {
    sort(tmp, tmp 
+ tmpsize);
    bin[ size 
= 1 ] = tmp[0];
    
for(int i = 1; i < tmpsize; i++{
        
if(fabs(tmp[i] - tmp[i-1]) > 1e-6)
            bin[ 
++size ] = tmp[i];
    }

}


int Binary(double v) {
    
int l = 1;
    
int r = size;

    
while(l <= r) {
        
int m = (l + r) >> 1;
        
if(fabs(v - bin[m]) < 1e-6)
            
return m;
        
if(v > bin[m])
            l 
= m + 1;
        
else
            r 
= m - 1;
    }

}


void Build(int p, int l, int r) {
    T[p].l 
= l;      T[p].r = r;
    T[p].p 
= p;
    T[p].nCover 
= 0; T[p].ylenOnce = T[p].ylenMore = 0;

    
if(l + 1 == r || l == 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(r <= T[p].l || l >= T[p].r)
        
return ;

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


    Insert(p
<<1, l, r, val);
    Insert(p
<<1|1, l, r, val);
    
    T[p].Update();
}

int n;
int main() {
    
int t;
    
int i;
    scanf(
"%d"&t);
    
while(t--{
        tmpsize 
= 0;
        Vl.clear();
        scanf(
"%d"&n);
        
for(i = 0; i < n; i++{
            
double x0, x1, y0, y1;
            scanf(
"%lf %lf %lf %lf"&x0, &y0, &x1, &y1);
            Vl.push_back(VLine(x0, y0, y1, 
1));
            Vl.push_back(VLine(x1, y0, y1, 
-1));
            tmp[ tmpsize
++ ] = y0;
            tmp[ tmpsize
++ ] = y1;
        }


        sort(Vl.begin(), Vl.end(), cmp);
        Process();
        Build(
11, size);
        
double ans = 0;
        
for(i = 0; i < Vl.size(); i++{
            
if(i) {
                ans 
+= (Vl[i].x - Vl[i-1].x) * T[1].ylenMore;
            }

            
int y1 = Binary(Vl[i].y1);
            
int y2 = Binary(Vl[i].y2);
            
if(y1 < y2)
                Insert(
1, y1, y2, Vl[i].val);
        }

        printf(
"%.2lf\n", ans);
    }

    
return 0;
}


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

评论

# re: HDU 1255 覆盖的面积  回复  更多评论   

受益匪浅,想大牛学习
2011-03-30 21:25 | 菜菜

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