HDU 1542 Atlantis
题目链接:HDU-1542
题意为给定许多个矩形,求面积的并。
基本的思路是首先把所有矩形按照下边高度从下往上排序,然后依次计算每两条边(上下边)之间夹的面积大小。
如图,每条绿色的线叫做扫描线。我们想要做到的事情是每次求出两条扫描线间的面积,如图中序号。显然,假设有n个矩形,则有2n条扫描线,我们需要求2n-1次面积。
要求面积,我们需要知道两条扫描线之间的高(很容易求)和当前扫描线扫描到的长度。
如图,即需要求出蓝色线段的长度。
我们首先把所有横坐标离散化,以此建立一棵线段树,线段树的每个节点表示离散化后的一个最小区间(即一个坐标到右边第一个坐标之间的区间)。我们用线段树维护每个区间被几条矩形的底边的投影所覆盖。同时利用这个信息,维护每个区间被覆盖的长度。
维护每个区间被几条矩形的底边的投影所覆盖,就等同于区间add的操作。每次扫到一个底边,就在底边对应的区间+1,若扫到一个顶边,则对应区间-1。这个操作是本题的核心所在,请仔细理解!
在每次更新“每个区间被几条矩形的底边的投影所覆盖”的mark值的同时,我们用如下方式维护每个区间被覆盖的长度sum。
if(mark[o]) sum[o]=(dict[r+1]-dict[l]); else if(l==r) sum[o]=0; else sum[o]=sum[o*2]+sum[o*2+1];
即若当前区间被完整覆盖(和被几条边覆盖无关),则sum等于区间对应长度。否则,sum等于两个自区间被覆盖的长度之和。
所以每次扫描完,只需在答案上加上sum[1]*h即可。
非常类似的题目还有HDU-1828
代码如下:
#include<cstdio> #include<set> #include<map> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int MAXN=2010; struct Line { int x1,x2,d; double y; bool operator < (Line x) { return y<x.y; } void operator = (Line x) { x1=x.x1; x2=x.x2; y=x.y; d=x.d; } }; double dict[MAXN]; map<double,int> index; double xx1[MAXN],xx2[MAXN],yy1[MAXN],yy2[MAXN]; set<double> S; Line lines[MAXN]; LL mark[MAXN<<2]; double sum[MAXN<<2]; void modify(LL o,LL l,LL r,LL ml,LL mr,LL num) { if(ml<=l && r<=mr) { mark[o]+=num; if(mark[o]) sum[o]=(dict[r+1]-dict[l]); else if(l==r) sum[o]=0; else sum[o]=sum[o*2]+sum[o*2+1]; } else { LL m=(r-l)/2+l; if(ml<=m) modify(o*2,l,m,ml,mr,num); if(mr>m) modify(o*2+1,m+1,r,ml,mr,num); if(mark[o]) sum[o]=(dict[r+1]-dict[l]); else if(l==r) sum[o]=0; else sum[o]=sum[o*2]+sum[o*2+1]; } } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int n,t=0; while(scanf("%d",&n)!=EOF && n) { int dictnum=0; index.clear(); S.clear(); memset(sum,0,sizeof(sum)); memset(mark,0,sizeof(mark)); double ans=0; printf("Test case #%d\n",++t); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf%lf",&xx1[i],&yy1[i],&xx2[i],&yy2[i]); S.insert(xx1[i]); S.insert(xx2[i]); } for(set<double>::iterator it=S.begin();it!=S.end();it++) { dict[++dictnum]=*it; index[*it]=dictnum; } for(int i=1;i<=n;i++) { Line tmp; tmp.x1=index[xx1[i]]; tmp.x2=index[xx2[i]]; tmp.y=yy1[i]; tmp.d=1; lines[2*i-1]=tmp; tmp.y=yy2[i]; tmp.d=-1; lines[2*i]=tmp; } sort(lines+1,lines+1+2*n); for(int now=1;now<=n*2-1;now++) { double h=lines[now+1].y-lines[now].y; Line ing=lines[now]; modify(1,1,dictnum-1,ing.x1,ing.x2-1,ing.d); ans+=h*sum[1]; //printf("%.2lf %.2lf %.2lf %.2lf\n",dict[ing.x1],dict[ing.x2],ing.y,ans); } printf("Total explored area: %.2lf\n\n",ans); } return 0; }