题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542
这个题目之前用线段切割方法做过,觉得做法经典,但是如果数据量大的话线段切割就力不从心了,后来尝试用线段树来解决
线段树方法也非常经典,由于开始有些细节没理解,用线段树一直都没能过,今天终于过了!
按照y坐标进行离散化解,之后不断插入竖线,用一颗线段树维护就行了
之前一直没能理解的是为什么标记是左边线段课右边线段就能判断当前面积能否是处在矩形内部
现在明白了,其实不难理解(但也不好说清楚),只是当时懒不愿意在纸上画画,这个方法仔细
读读代码,仔细在纸上画一遍就都明白了!
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <set>
#include <vector>
#include <map>
using namespace std;
#define maxn 20000
struct line{
double x,y1,y2;
int flag;
line(){}
line(double _x,double _y1,double _y2,int f):x(_x),y1(_y1),y2(_y2),flag(f){}
bool operator < (const line &a) const{
return x < a.x;
}
};
struct point{
int l,r,flag;
double total;
}po[maxn*4];
int n;
vector<double> y;
vector<line>li;
map<double ,int> m;
int build_tree(int root,int l,int r){
po[root].l=l,po[root].r=r;
po[root].flag=0,po[root].total=0;
if(l+1 == r) return 0;
int mid=(l+r)>>1;
build_tree(root<<1,l,mid);
build_tree((root<<1)+1,mid,r);
return 0;
}
int insert(int root,int l,int r,int flag){
if(po[root].l+1 == po[root].r){
po[root].flag+=flag;
if(po[root].flag==0) po[root].total=0;
else po[root].total=y[r]-y[l];
}
else{
int mid=(po[root].l+po[root].r)>>1;
if(l>=mid) insert((root<<1|1),l,r,flag);
else if(r<=mid) insert(root<<1,l,r,flag);
else insert(root<<1,l,mid,flag),insert((root<<1|1),mid,r,flag);
po[root].total=po[root<<1].total+po[(root<<1|1)].total;
}
return 0;
}
int main(){
int i,j,k,cas=0;
double x1,y1,x2,y2,ans;
while(scanf("%d",&n),n){
m.clear();y.clear();li.clear();
for(i=0;i<n;i++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
li.push_back(line(x1,y1,y2,-1));
li.push_back(line(x2,y1,y2,1));
y.push_back(y1),y.push_back(y2);
}
sort(li.begin(),li.end());
sort(y.begin(),y.end());
y.erase(unique(y.begin(),y.end()),y.end());
for(i=0;i<y.size();i++) m[y[i]]=i;
build_tree(1,0,y.size()-1);
ans=0;
for(i=0;i<li.size();i++){
if(i!=0) ans+=(li[i].x-li[i-1].x)*po[1].total;
insert(1,m[li[i].y1],m[li[i].y2],li[i].flag);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",++cas,ans);
}
return 0;
}