/*这个很多参考了NotOnlySuccess的思路。cnt用的记为精妙啊。 将区间起始端点标记为1,末端点标记为-1. 则进入一个矩形为1,离开一个矩形为-1,cnt不为0表示线段有重叠。 先对纵坐标进行排序,在x轴上求相应区间的最大值,取根节点即可。*/ #include <stdio.h> #include <algorithm> #include <iostream> #include <cstring> #define maxn 2222 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 double sum[maxn<<2]; int cnt[maxn<<2]; double X[maxn]; struct seg { double l, r, h;//标记线段的始末 int s; seg() {} seg(double a,double b,double c,int d):l(a),r(b),h(c),s(d) {} bool operator < (const seg&cmp)const { return h<cmp.h; } } ss[maxn<<2]; void pushup(int rt,int l,int r) { if(cnt[rt]) sum[rt]=X[r+1]-X[l]; else if(l==r) sum[rt]=0; else sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void update(int a,int b,int c,int l,int r,int rt) { if(a<=l&&b>=r) { cnt[rt]+=c; pushup(rt,l,r); return ; } int mid=(r+l)>>1; if(a<=mid) update(a,b,c,lson); if(b>mid) update(a,b,c,rson); pushup(rt,l,r); } int binary(double key,int n,double X[]) { int low=0,high=n-1; while(low<=high) { int m=(low+high)>>1; if(X[m]==key) return m; else if(X[m]<key) low=m+1; else high=m-1; } return -1; } using namespace std; int main() { int n; double a,b,c,d; int cases=1; while(scanf("%d",&n)==1&&n) { int m=0; for(int i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&a,&b,&c,&d); X[m]=a; ss[m++]=seg(a,c,b,1); X[m]=c; ss[m++]=seg(a,c,d,-1); } sort(X,X+m); sort(ss,ss+m); int nn=1; for(int i=1;i<m;i++) { if(X[i]!=X[i-1]) X[nn++]=X[i]; } double ret=0; memset(cnt,0,sizeof(cnt)); memset(sum,0,sizeof(sum)); for(int i=0;i<m;i++)//在离散化后的数组里进行查询 { int l=binary(ss[i].l,nn,X); int r=binary(ss[i].r,nn,X)-1; if(l<=r) { update(l,r,ss[i].s,0,nn-1,1); ret+=sum[1]*(ss[i+1].h-ss[i].h); } } printf("Test case #%d\n",cases++); printf("Total explored area: %.2lf\n",ret); printf("\n"); } return 0; }
Atlantis 线段树经典问题 矩形面积并
最新推荐文章于 2023-06-02 00:08:09 发布