求矩形面积并,离散化加线段树。
扫描线法:
用平行x轴的直线扫,每次ans+=(下一个高度-当前高度)*当前覆盖的宽度。
#include<algorithm> #include<cstdio> #include<cstring> #define dd double #define ll long long #define N 201 using namespace std; struct P{dd s,e,h;int f;}p[N]; struct Tree{dd sum;int c;}t[N<<5]; dd a,b,c,d,x[N],ans; int n,m,num; int cmp(const P &a,const P &b){ return a.h<b.h; } void pushUp(ll rt,ll l,ll r){ if(t[rt].c)t[rt].sum=x[r+1]-x[l];//r+1是因为节点[l,r]表示区间[x[l],x[r+1]]。 else if(l==r)t[rt].sum=0; else t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum; } void update(ll s,ll e,ll rt,ll l,ll r,ll v){ if(s<=l&&r<=e) t[rt].c+=v; else { if(l>e||r<s)return; ll m=l+r>>1; update(s,e,rt<<1,l,m,v); update(s,e,rt<<1|1,m+1,r,v); } pushUp(rt,l,r); } int main() { while(scanf("%d",&n),n){ int k=0; for(int i=0;i<n;i++){ scanf("%lf%lf%lf%lf",&a,&b,&c,&d); x[++k]=a,p[k]=(P){a,c,b,1}; x[++k]=c,p[k]=(P){a,c,d,-1}; } sort(x+1,x+1+k); sort(p+1,p+1+k,cmp); m=1; for(int i=1;i<=k;i++) if(x[i]!=x[i-1])x[m++]=x[i]; ans=0; for(int i=1;i<=k;i++){//共k条线段,每次计算p[i].h到p[i+1].h之间的面积,第k次相当于清空所有,酱就不用初始化线段树了。 int l=lower_bound(x,x+m,p[i].s)-x; int r=lower_bound(x,x+m,p[i].e)-x-1;//r-1同上原因 update(l,r,1,0,m-1,p[i].f); ans+=t[1].sum*(p[i+1].h-p[i].h); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",++num,ans); } return 0; }
另一种方法还是线段树,这里扫描线用的是平行y轴的直线,每次增加的面积是当前扫描的竖线所在的高度区间的最后一次的x与当前x的差值乘上区间的高度。所以每次增加的不一定是一个矩形,而是多个矩形并。
#include<cstdio> #include<algorithm> #define dd double using namespace std; #define N 201 struct P{dd x,y1,y2;int f;}p[N]; struct TREE{dd y1,y2,x;int c,f;}tree[N<<5]; dd x1,y1,x2,y2,y[N]; int n,k,num; int cmp(const P &a,const P &b){ return a.x<b.x; } void build(int i,int l,int r){ tree[i].c=tree[i].f=0; tree[i].y1=y[l];//直接将线段树节点代表的区间存在线段树里 tree[i].y2=y[r]; if(l+1==r){ tree[i].f=1; return; } int mk=(l+r)>>1; build(i<<1,l,mk); build(i<<1|1,mk,r); } dd insert(int i,dd x,dd l,dd r,int flag){ if(r<=tree[i].y1||l>=tree[i].y2) return 0; if(tree[i].f){//离散后的一个最小区间,叶子节点 dd ans; if(tree[i].c>0)//全覆盖 ans=(x-tree[i].x)*(tree[i].y2-tree[i].y1);//(当前x-该区间最后的x)*区间高度 else ans=0; tree[i].x=x;//该区间最新的x tree[i].c+=flag;//更新覆盖 return ans; } return insert(i<<1,x,l,r,flag)+insert(i<<1|1,x,l,r,flag); } int main(){ while(scanf("%d",&n),n){ k=0; for(int i=1;i<=n;i++){ scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); y[++k]=y1,p[k]=(P){x1,y1,y2,1}; y[++k]=y2,p[k]=(P){x2,y1,y2,-1}; } sort(y+1,y+k+1); sort(p+1,p+k+1,cmp); //没有去重,其实数量少,没必要。 build(1,1,k); dd ans=0; for(int i=1;i<=k;i++) ans+=insert(1,p[i].x,p[i].y1,p[i].y2,p[i].f); printf("Test case #%d\nTotal explored area: %.2f\n\n",++num,ans); } return 0; }
时间: 2024-12-21 17:42:49