题目链接
这是求面积并的题目,刚开始我的思路是将挖去的矩形的入边和出边覆盖效果颠倒,
即入边-1,出边+1,后来调试到爆炸,发现这是错误的做法。。原因就是对最简单
的面积并问题没有搞清楚。刚开始接触扫描线的时候我就有一个问题,为什么覆盖
次数不需要向子区间传递,但是我没有仔细去想这个问题,直到遇到这道题目。在
求相交矩形面积并的过程中,所有的线段都是成对出现,重点在于所有线段的覆盖
都是整段整段的操作,所以不需要向下传。而这道题目用这种做法就会出现一个区
间被较小的区间释放的情况,所以会出错。
#include<cstdio> #include<algorithm> using namespace std; const int maxn=310;//最多矩形个数 struct edge{int x1,x2,y;int f;//1表示入,-1表示出 edge(){}edge(int _x1,int _x2,int _y,int _f){x1=_x1,x2=_x2,y=_y,f=_f;}bool operator <(edge &e){if(y!=e.y)return y<e.y;return f>e.f;} }; int nVx; int Vx[maxn*4]; int nSgs; edge Sgs[maxn*4]; int num[maxn*4*4]; int len[maxn*4*4]; void build(int root,int l,int r) {num[root]=len[root]=0;if(l==r)return;int mid=(l+r)/2;build(root*2,l,mid);build(root*2+1,mid+1,r); } void pushUp(int root,int l,int r) {if(num[root]!=0)len[root]=Vx[r+1]-Vx[l];else if(l==r)len[root]=0;else len[root]=len[root*2]+len[root*2+1];printf("%d %d num[%d]=%d\n",l,r,root,num[root]); } void update(int root,int L,int R,int f,int l,int r) {//printf("%d %d %d %d %d %d\n",root,L,R,f,l,r);if(L<=l&&r<=R){num[root]+=f;pushUp(root,l,r);return ;}int mid=(l+r)/2;if(L<=mid)update(root*2,L,R,f,l,mid);if(mid<R)update(root*2+1,L,R,f,mid+1,r);pushUp(root,l,r); } int bin(int k) {int l=0,r=nVx-1,mid;while(l<=r){mid=(l+r)/2;if(Vx[mid]==k)return mid;else if(Vx[mid]>k)r=mid-1;else l=mid+1;}return -1; } int myUnique(int a[],int n) {int sz=1;for(int i=1;i<n;i++){if(a[i]!=a[i-1])a[sz++]=a[i];}return sz; } int main() {freopen("in.txt","r",stdin);int N;while(scanf("%d",&N)!=EOF&&N!=0){nVx=0;nSgs=0;for(int i=0;i<N;i++){int x1,y1,x2,y2,x3,y3,x4,y4;scanf("%d%d%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);printf("%d %d %d %d %d %d %d %d\n",x1,y1,x2,y2,x3,y3,x4,y4);Vx[nVx++]=x1,Vx[nVx++]=x2,Vx[nVx++]=x3,Vx[nVx++]=x4;Sgs[nSgs++]=edge(x1,x2,y1,1);Sgs[nSgs++]=edge(x1,x2,y2,-1);Sgs[nSgs++]=edge(x3,x4,y3,-1);Sgs[nSgs++]=edge(x3,x4,y4,1);}sort(Vx,Vx+nVx);nVx=myUnique(Vx,nVx);sort(Sgs,Sgs+nSgs);build(1,0,nVx-1);int area=0;for(int i=0;i<nSgs-1;i++){int l=bin(Sgs[i].x1);int r=bin(Sgs[i].x2)-1;update(1,l,r,Sgs[i].f,0,nVx-1);printf("%d %d\n",len[1],Sgs[i+1].y-Sgs[i].y);area+=len[1]*(Sgs[i+1].y-Sgs[i].y);}printf("%d\n",area);}while(1); }
先贴一下思路:海报一张可以切割成4个矩形,然后就是普通的矩形面积并了,利
用线段树维护即可
正确做法
#include<cstdio> #include<algorithm> using namespace std; const int maxn=50310;//最多矩形个数 struct edge{int x1,x2,y;int f;//1表示入,-1表示出 edge(){}edge(int _x1,int _x2,int _y,int _f){x1=_x1,x2=_x2,y=_y,f=_f;}bool operator <(edge &e){if(y!=e.y)return y<e.y;return f>e.f;} }; int nSgs; edge Sgs[maxn*8]; int num[maxn*8]; int len[maxn*8]; void build(int root,int l,int r) {num[root]=len[root]=0;if(l==r)return;int mid=(l+r)/2;build(root*2,l,mid);build(root*2+1,mid+1,r); } void pushUp(int root,int l,int r) {if(num[root]!=0)len[root]=r-l+1;else if(l==r)len[root]=0;else len[root]=len[root*2]+len[root*2+1];//printf("%d %d num[%d]=%d\n",l,r,root,num[root]); } void update(int root,int L,int R,int f,int l,int r) {//printf("%d %d %d %d %d %d\n",root,L,R,f,l,r);if(L<=l&&r<=R){num[root]+=f;pushUp(root,l,r);return ;}int mid=(l+r)/2;if(L<=mid)update(root*2,L,R,f,l,mid);if(mid<R)update(root*2+1,L,R,f,mid+1,r);pushUp(root,l,r); } int main() {//freopen("in.txt","r",stdin);int N;while(scanf("%d",&N)!=EOF&&N!=0){nSgs=0;int lb=0,rb=maxn;for(int i=0;i<N;i++){int x1,y1,x2,y2,x3,y3,x4,y4;scanf("%d%d%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);Sgs[nSgs++]=edge(x1,x2,y1,1);Sgs[nSgs++]=edge(x1,x2,y3,-1);Sgs[nSgs++]=edge(x1,x3,y3,1);Sgs[nSgs++]=edge(x1,x3,y4,-1);Sgs[nSgs++]=edge(x4,x2,y3,1);Sgs[nSgs++]=edge(x4,x2,y4,-1);Sgs[nSgs++]=edge(x1,x2,y4,1);Sgs[nSgs++]=edge(x1,x2,y2,-1);lb=min(x1,lb);rb=max(x2,rb);}sort(Sgs,Sgs+nSgs);build(1,lb,rb);long long area=0;for(int i=0;i<nSgs-1;i++){int l=Sgs[i].x1;int r=Sgs[i].x2-1;if(l<=r)update(1,l,r,Sgs[i].f,lb,rb-1);//printf("%d %d\n",len[1],Sgs[i+1].y-Sgs[i].y);area+=(long long)len[1]*(Sgs[i+1].y-Sgs[i].y);}printf("%lld\n",area);}//while(1); }
参考资料
http://www.cnblogs.com/--ZHIYUAN/p/6404732.html