要求矩形的面积并
代码不复杂,主要要理解扫描线的思想以及一些细节的处理。
首先需要将接收到的x坐标离散化,方法就是排序去重。接下来的线段树建立在这个
关于x坐标的数组上,这很关键。线段树的节点代表一段区间,这个区间是由x坐标数组的下标
来构成的。更新的时候就根据水平线段的左右x坐标获得区间,然后更新区间。
看了这么多,离散化之后关于r+1,r-1的问题还是很模糊。
我尽力理解一下,有一个[0,4]的区间,叶节点分别为[0,0],[1,1],[2,2],[3,3],[4,4],
那么[0,0]节点表示的是区间[0,1];[1,1]节点表示的区间[1,2];[2,2]节点表示的区间[2,3];[3,3]节点表示区间[3,4];
当向上传递时[0,1]节点表示区间[0,2],以此类推
#include<cstdio> #include<algorithm> #include<vector> using namespace std; const int maxn=110;//最多矩形个数 struct seg{ double lx,rx,y; short f; seg(){} seg(double lx_,double rx_,double y_,short f_):lx(lx_),rx(rx_),y(y_),f(f_){} bool operator <(const seg &a)const { return y<a.y; } }; int sgsNum; seg sgs[maxn*2]; int x2nNum; //x2n double x2n[maxn*2]; double len[maxn*8]; int num[maxn*8]; void build(int root,int l,int r) { len[root]=num[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]){ len[root]=x2n[r+1]-x2n[l]; }else if(l==r){ len[root]=0; } else { len[root]=len[root*2]+len[root*2+1]; } } void update(int root,int L,int R,int f,int l,int r) { if(L<=l&&r<=R){ num[root]+=f; pushUp(root,l,r); return; } int mid=l+(r-l)/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(double k) { int m,l=0,r=x2nNum-1; while(l<=r){ m=(l+r)/2; if(x2n[m]==k)return m; else if(x2n[m]>k)r=m-1; else l=m+1; } return -1; } int main() { //freopen("in.txt","r",stdin); int n,p=0; while(scanf("%d",&n)!=EOF&&n!=0){ sgsNum=0,x2nNum=0; p++; for(int i=0;i<n;i++){ double lx,ly,rx,ry; scanf("%lf%lf%lf%lf",&lx,&ly,&rx,&ry); sgs[sgsNum++]=seg(lx,rx,ly,1); sgs[sgsNum++]=seg(lx,rx,ry,-1); x2n[x2nNum++]=lx; x2n[x2nNum++]=rx; } double area=0; sort(x2n,x2n+x2nNum); sort(sgs,sgs+sgsNum); x2nNum=unique(x2n,x2n+x2nNum)-x2n; build(1,0,x2nNum-1); for(int i=0;i<sgsNum-1;i++){ int l=bin(sgs[i].lx); int r=bin(sgs[i].rx)-1; update(1,l,r,sgs[i].f,0,x2nNum-1); area+=len[1]*(sgs[i+1].y-sgs[i].y); } printf("Test case #%d ",p); printf("Total explored area: %.2lf ",area); } //while(1); }
参考资料