POJ1151-Atlantis
chunlvxiong的博客
题目描述:
有n个矩形(1≤n≤100),它们之间可能会重叠,输出其总面积。
思考&分析:
很容易想到先把所有矩形的x,y坐标离散化,然后你可以对于每个矩形O(N^2)暴力覆盖,最后O(N^2)统计即可,时间复杂度O(N^3),可以A掉此题,但是我们有优秀地多的做法。
你可以考虑先将矩形按照x坐标排序,然后按照x坐标从小到大扫过去,如果遇到的x坐标是一个矩形的开头,那么暴力O(N)覆盖其y坐标的范围,如果遇到的x坐标是一个矩形的结尾,也同样取消覆盖其y坐标的范围,对于每个x,O(N)扫统计出其y坐标上的总长度(可能由好几段组成),然后*对应x坐标的长度即可,时间复杂度O(N^2)。
看看这幅图,你每次统计的部分就是涂上斜线的部分。
然后这个O(N^2)是可以优化成O(NlogN)的-->相信大家都已经猜到用线段树优化了。
顺带一提,虽然是区间修改,但是这个线段树并不用lazy标记,原因很简单,标记和删除的空间总是对应相同的。
贴代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int maxn=205; int cnt_x,cnt_y,all_x,all_y; double hash_x[maxn],hash_y[maxn]; double a1[maxn],b1[maxn],a2[maxn],b2[maxn]; int n; struct seg{ double sum; int cover; }tree[maxn*4]; struct point{ int x,y; }; struct ju{ point a,b; }P[maxn],p[maxn]; bool cmp(double a,double b){ return a<b; } void LSH(){ sort(hash_x+1,hash_x+cnt_x+1,cmp); sort(hash_y+1,hash_y+cnt_y+1,cmp); all_x=1; for (int i=2;i<=cnt_x;i++) if (fabs(hash_x[i]-hash_x[i-1])>1e-8) hash_x[++all_x]=hash_x[i]; all_y=1; for (int i=2;i<=cnt_y;i++) if (fabs(hash_y[i]-hash_y[i-1])>1e-8) hash_y[++all_y]=hash_y[i]; } int find_x(double x){ int L=1,R=all_x,mid=(L+R)>>1; while (fabs(hash_x[mid]-x)>1e-8){ if (hash_x[mid]<x) L=mid+1; else R=mid-1; mid=(L+R)>>1; } return mid; } int find_y(double y){ int L=1,R=all_y,mid=(L+R)>>1; while (fabs(hash_y[mid]-y)>1e-8){ if (hash_y[mid]<y) L=mid+1; else R=mid-1; mid=(L+R)>>1; } return mid; } bool cmp1(ju a,ju b){ return a.a.x<b.a.x; } bool cmp2(ju a,ju b){ return a.b.x<b.b.x; } void build(int rt,int L,int R){ tree[rt].sum=tree[rt].cover=0; if (L==R) return; int mid=(L+R)>>1; build(rt<<1,L,mid); build((rt<<1)|1,mid+1,R); } void pushup(int rt,int L,int R){ if (tree[rt].cover) tree[rt].sum=hash_y[R+1]-hash_y[L]; else if (L==R) tree[rt].sum=0; else tree[rt].sum=tree[rt<<1].sum+tree[(rt<<1)|1].sum; } void change(int rt,int L,int R,int CL,int CR,int v){ if (CL>R || CR<L) return; if (CL<=L && CR>=R){ tree[rt].cover+=v; pushup(rt,L,R); return; } int mid=(L+R)>>1; change(rt<<1,L,mid,CL,CR,v); change((rt<<1)+1,mid+1,R,CL,CR,v); pushup(rt,L,R); } int main(){ int Case=0; while (~scanf("%d",&n)){ if (!n) break; cnt_x=cnt_y=0; for (int i=1;i<=n;i++){ scanf("%lf%lf%lf%lf",&a1[i],&a2[i],&b1[i],&b2[i]); hash_x[++cnt_x]=a1[i],hash_x[++cnt_x]=b1[i]; hash_y[++cnt_y]=a2[i],hash_y[++cnt_y]=b2[i]; } LSH(); for (int i=1;i<=n;i++){ P[i].a.x=find_x(a1[i]),P[i].a.y=find_y(a2[i]); P[i].b.x=find_x(b1[i]),P[i].b.y=find_y(b2[i]); p[i]=P[i]; } sort(P+1,P+n+1,cmp1); sort(p+1,p+n+1,cmp2); build(1,1,all_y-1); double ans=0; for (int X=1,i=1,j=1;X<all_x;X++){ while (i<=n && P[i].a.x==X){ change(1,1,all_y-1,P[i].a.y,P[i].b.y-1,1); i++; } while (j<=n && p[j].b.x==X){ change(1,1,all_y-1,p[j].a.y,p[j].b.y-1,-1); j++; } ans+=(hash_x[X+1]-hash_x[X])*tree[1].sum; } printf("Test case #%d\n",++Case); printf("Total explored area: %.2lf\n",ans); puts(""); } return 0; }