线段树+离散化+矩形面积求并。做完了前面比较简单的 POJ3277,再做这一题就知道怎么下手了。开始的时候我只打印一个算的面积,然后很果断的wrong了,之后就没想这道题目了,当我做其它题目的时 候,突然想起来,我没按照格式输出啊(狂晕)。然后我又将输出结果改了一下,一交PE了。哇咔咔,忽略了空行,。加了空行就过了,。
说下这个题目的思路,先离散化,由于只有200个矩形,也就 是最多只有400个点,(以x轴算),那么我们就可以将与y轴平行的边投影成点,然后将这些点排个序,去除重复的点,然后以这些点来建线段树。线段树中保 存当前矩形的上下边的坐标以及对应的区间的和。建树的方式和POJ3277相同,以下标建树。用个数组来保存对应值。然后我们将原来的矩形按照y轴的坐标 进行排序,要求底边坐标小的在前,相同的坐标,上边小的在前。
然后我们不断的插入矩形。从前往后插入。设现在有矩形a和b。如果a,b在同一个区间内(即a,b的x坐标相同),那么先插入的必定是y坐标比较小的,后插入的是y坐标比较大的,如果已经插入矩形a ,当插入矩形b的时候,如果a,b无共同区域,也即不相交,此时我们需要求出先插入的矩形a的面积,并累加到当前的线段树节点中,然后我们用带插入的矩形来更新当前节点的值。而如果两个矩形有相同的区域,那么必定可以将两个矩形合并成一个大的矩形,(因为两个矩形的x坐标是相同的,而y坐 标不同)。而如果插入的时候, a和b的x坐标范围只是部分重叠,那么我们需要先将当前节点的a更新到子树中,而在子树中只可能出现如下情况:如果子树区间中已经有矩形,那么该矩形的x坐标范围一定是当前节点中的x坐标区间范围,那么我们就可以向前面那样,分成两种情况,两个矩形有共同区间与没有共同区间。如果子树区间中没有矩形,我们直接将其插入到其中即可。然后在将需要插入的树,插入即可。
统计的时候,我们只需要累加每个节点的sum值,对于每个元线段,我们直接按照矩形的面积计算公式计算,而非元线段我们就需要将父节点的值更新到子节点,然后在统计。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std ;
#define MAXN 10000
struct Rectangle
{
double x1 ;
double x2 ;
double y1 ;
double y2 ;
};
struct SegmentTree
{
int l ;
int r ;
double bottom ;
double top ;
double sum ;
};
bool cmp(Rectangle a , Rectangle b){
if(a.y1 != b.y1)
return a.y1 < b.y1 ;
else
return a.y2 < b.y2 ;
}
Rectangle line[MAXN] ;
SegmentTree tree[MAXN] ;
double Sline[MAXN] ;
int n ;
int m ;
bool input(){
scanf("%d" , &n) ;
m = 0 ;
for(int i = 1 ; i <= n ; i ++){
scanf("%lf%lf%lf%lf" , &line[i].x1 , &line[i].y1 , &line[i].x2 , &line[i].y2) ;
Sline[++m] = line[i].x1 ;
Sline[++m] = line[i].x2 ;
}
return n ;
}
int inline M(int x , int y){
return (x + y)>>1 ;
}
int inline L(int x){
return x<<1 ;
}
int inline R(int x){
return x<<1|1 ;
}
void build(int l , int r , int c){
tree[c].l = l ;
tree[c].r = r ;
tree[c].sum = 0.0 ;
tree[c].bottom = 0.0 ;
tree[c].top = 0.0 ;
if(l + 1 == r)
return ;
build(l , M(l , r) , L(c)) ;
build(M(l , r) , r , R(c)) ;
}
void pushdown(int c){
int l = L(c) ;
int r = R(c) ;
//如果两个矩形不重合
if(tree[c].bottom >= tree[l].top){
tree[l].sum += (Sline[ tree[l].r ] - Sline[ tree[l].l ]) * (tree[l].top - tree[l].bottom) ;
tree[l].top = tree[c].top ;
tree[l].bottom = tree[c].bottom ;
}
//有相同的区域,合并成一个新的矩形
else if(tree[c].bottom > tree[l].bottom && tree[c].bottom < tree[l].top) {
tree[l].top = tree[l].top > tree[c].top ? tree[l].top : tree[c].top ;
tree[l].bottom = tree[l].bottom > tree[c].bottom ? tree[c].bottom : tree[l].bottom ;
}
if(tree[c].bottom >= tree[r].top){
tree[r].sum += (Sline[ tree[r].r ] - Sline[tree[r].l]) *(tree[r].top - tree[r].bottom) ;
tree[r].top = tree[c].top ;
tree[r].bottom = tree[c].bottom ;
}
else if(tree[c].bottom > tree[r].bottom && tree[c].bottom < tree[r].top){
tree[r].top = tree[c].top > tree[r].top ? tree[c].top : tree[r].top ;
tree[r].bottom = tree[r].bottom > tree[c].bottom ? tree[c].bottom : tree[r].bottom ;
}
tree[c].top = 0.0 ;
tree[c].bottom = 0.0 ;
}
void insert(double l , double b , double r , double t , int c){
//如果插入的区间是相同的,我们就比较两个矩形是不是有重合的
//区间,如果有则更新成一个新的矩形,否则将之前插入的矩形的
//面积计算出来并累加到当前节点的sum值中,然后更新一下当前的节点的矩形
if( l == Sline[ tree[c].l ] && r == Sline[ tree[c].r ] ){
if(tree[c].bottom <= b && tree[c].top >= b){
if(tree[c].top < t)
tree[c].top = t ;
}
else if(tree[c].top < b){
tree[c].sum += (Sline[ tree[c].r ] - Sline[ tree[c].l ])*(tree[c].top - tree[c].bottom) ;
tree[c].bottom = b ;
tree[c].top = t ;
}
return ;
}
if(tree[c].l + 1 == tree[c].r)
return ;
//更新子节点的值
pushdown(c) ;
int m = M(tree[c].l , tree[c].r) ;
if(Sline[m] >= r){
insert(l , b , r , t , L(c) ) ;
}
else if(Sline[m] <= l){
insert(l , b , r , t , R(c) ) ;
}
else {
insert(l , b , Sline[m] , t , L(c)) ;
insert(Sline[m] , b , r , t , R(c)) ;
}
}
void query(double &ans , int c){
//累加每个节点的sum值
ans += tree[c].sum ;
//只统计元线段中的值
if(tree[c].l + 1 == tree[c].r){
ans += (tree[c].top - tree[c].bottom) *( Sline[ tree[c].r ] - Sline[ tree[c].l ] ) ;
return ;
}
//向下更新
pushdown(c) ;
query(ans , L(c)) ;
query(ans , R(c)) ;
}
void solve(){
//进行里离散化+排序
sort(Sline + 1 , Sline + m + 1) ;
sort(line + 1 , line + n + 1 , cmp) ;
m = unique(Sline + 1 , Sline + m + 1) - Sline - 1 ;
build(1 , m , 1) ;
for(int i = 1 ; i <= n ; i ++){
insert(line[i].x1 , line[i].y1 , line[i].x2 , line[i].y2 , 1) ;
}
double ans = 0.0 ;
query(ans , 1) ;
printf("Total explored area: %.2lf\n" , ans) ;
}
int main(){
int t ;
t = 1 ;
while(input()){
printf("Test case #%d\n" , t++) ;
solve() ;
printf("\n") ;
}
return 0 ;
}