http://acm.hdu.edu.cn/showproblem.php?pid=1542
题意:求矩形的并面积
思路:扫描线
扫描线:把每一条平行于y轴的边,打上标记,矩形左边为正,右边为负。沿着x轴从左往右扫。离散化y轴,缩区间为点。在线段树上维护y轴。虽然是区间加操作,但是因为区间减时,必然是已经加过的值,在pushUp的地方修改一下就不需要pushDown了。
扫描线是真·区间操作,返回的时候 l+1==r
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int MX = 1e5+5;
struct no{double x,uy,dy;int ior;};
bool operator<(const no &x,const no &y) {return x.x<y.x;}
vector<no>line;
vector<double>v;
int cover[MX];
double le[MX];
void pushUp(int l,int r,int rt){
if(cover[rt]) le[rt]=v[r]-v[l];//可能覆盖之前的
else if(l+1==r)le[rt]=0;//叶子节点
else le[rt]=le[rt<<1]+le[rt<<1|1]; //没有标记了,由儿子得到
}
void update(int L,int R,int io,int l,int r,int rt){
if(l>=L&&r<=R) {
cover[rt]+=io;pushUp(l,r,rt);return ;
}
if(l+1==r)return ; //到叶子节点,区间长度为2,必须返回
int m=(l+r)>>1;
if(L<=m) update(L,R,io,l,m,rt<<1);
if(R>=m) update(L,R,io,m,r,rt<<1|1);//这里不再是m+1,因为要进入类似[1,2][2,3]的叶子节点
pushUp(l,r,rt);
}
int main(){
int n,casen=0;
while(cin>>n){
if(n==0)break;
line.clear(),v.clear();
for(int i=1;i<=n;i++){
cover[i]=le[i]=0;
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
v.push_back(y1),v.push_back(y2);
line.push_back(no{x1,y2,y1,1});
line.push_back(no{x2,y2,y1,-1});
}
sort(line.begin(),line.end());
sort(v.begin(),v.end());//离散化
v.erase(unique(v.begin(),v.end()),v.end());
double ans=0;
for(int i=0;i<(int)line.size();i++){
if(i>0) ans+=le[1]*(line[i].x-line[i-1].x);
int yl=lower_bound(v.begin(),v.end(),line[i].dy)-v.begin();
int yr=lower_bound(v.begin(),v.end(),line[i].uy)-v.begin();
update(yl,yr,line[i].ior,0,(int)v.size()-1,1);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",++casen,ans);
}
return 0;
}