线段树扫描线(一、Atlantis HDU - 1542(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))
扫描线求周长: hdu1828 Picture(线段树+扫描线+矩形周长)
参考链接:https://blog.csdn.net/konghhhhh/java/article/details/78236036
假想有一条扫描线,从左往右(从右往左),或者从下往上(从上往下)扫描过整个多边形(或者说畸形。。多个矩形叠加后的那个图形)。如果是竖直方向上扫描,则是离散化横坐标,如果是水平方向上扫描,则是离散化纵坐标。下面的分析都是离散化横坐标的,并且从下往上扫描的。
扫描之前还需要做一个工作,就是保存好所有矩形的上下边,并且按照它们所处的高度进行排序,另外如果是上边我们给他一个值-1,下边给他一个值1,我们用一个结构体来保存所有的上下边
struct segment
{
double l,r,h; //l,r表示这条上下边的左右坐标,h是这条边所处的高度
int f; //所赋的值,1或-1
}
接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),这个投影对应的其实是个插入和删除线段操作。还记得给他们赋的值1或-1吗,下边是1,扫描到下边的话相当于往总区间插入一条线段,上边-1,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,对应的那一段的值都要增1,扫描到上边对应的那一段的值都要减1,如果总区间某一段的值为0,说明其实没有线段覆盖到它,为正数则有,那会不会为负数呢?是不可能的,可以自己思考一下)。
每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积
(这个过程其实一点都不难,只是看文字较难体会,建议纸上画图,一画即可明白,下面献上一图希望有帮助)
例题:一、Atlantis HDU - 1542(覆盖面积)
题意:
给你一些矩形,让你求出来它们的总面积是多少(注意这些矩形可能会重叠)
题解:
就是上面讲的扫描线方法
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 #define lson i<<1,l,m 7 #define rson i<<1|1,m+1,r 8 const int maxn=205; 9 double w[maxn<<1]; 10 struct trees 11 { 12 double l,r,h; 13 int d; 14 trees() {} 15 trees(double a,double b,double c,int d): l(a),r(b),h(c),d(d) {} 16 bool operator <(const trees q)const 17 { 18 return h<q.h; 19 } 20 } tree[maxn<<2]; 21 int cnt[maxn<<2]; 22 double sum[maxn<<2]; 23 void pushdown(int rt,int l,int r) 24 { 25 int m=(l+r)>>1; 26 if(cnt[rt]!=-1) 27 { 28 cnt[rt<<1]=cnt[rt<<1|1]=cnt[rt]; 29 sum[rt<<1]=(cnt[rt] ? (w[m+1]-w[l]) : 0); 30 sum[rt<<1|1]=(cnt[rt] ? (w[r+1]-w[m+1]) : 0); 31 } 32 } 33 void pushup(int rt,int l,int r) 34 { 35 if(cnt[rt<<1] || cnt[rt<<1|1]) 36 { 37 cnt[rt]=-1; 38 } 39 else if(cnt[rt<<1]!=cnt[rt<<1|1]) 40 { 41 cnt[rt]=-1; 42 } 43 else cnt[rt]=cnt[rt<<1]; 44 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 45 } 46 void build(int rt,int l,int r) 47 { 48 if(l==r) 49 { 50 sum[rt]=0.0; 51 cnt[rt]=0; 52 return; 53 } 54 int m=(l+r)>>1; 55 build(rt<<1,l,m); //就是这里rt<<1的位置写错了,卧槽。。 56 build(rt<<1|1,m+1,r); 57 pushup(rt,l,r); 58 } 59 void update(int L,int R,int C,int rt,int l,int r) 60 { 61 if(l>=L && r<=R) 62 { 63 if(cnt[rt]!=-1) 64 { 65 cnt[rt]+=C; 66 sum[rt]=(cnt[rt] ? (w[r+1]-w[l]) : 0); 67 return; 68 } 69 } 70 pushdown(rt,l,r); 71 int m=(l+r)>>1; 72 if(m>=L) update(L,R,C,rt<<1,l,m); 73 if(R>m) update(L,R,C,rt<<1|1,m+1,r); 74 pushup(rt,l,r); 75 } 76 int searchs(int l,int r,double x) 77 { 78 int m=-1; 79 while(l<=r) 80 { 81 m=(l+r)>>1; 82 if(w[m]>x) r=m-1; 83 else if(w[m]<x) l=m+1; 84 else break; 85 } 86 return m; 87 } 88 //void PushDown(int i,int l,int r) 89 // 90 //{ 91 // 92 // int m=(l+r)/2; 93 // 94 // if(cnt[i]!=-1) 95 // 96 // { 97 // 98 // cnt[i*2]=cnt[i*2+1]=cnt[i]; 99 // 100 // sum[i*2]= (cnt[i]?(w[m+1]-w[l]):0) ; 101 // 102 // sum[i*2+1]= (cnt[i]?(w[r+1]-w[m+1]):0) ; 103 // 104 // } 105 // 106 //} 107 // 108 //void PushUp(int i,int l,int r) 109 // 110 //{ 111 // 112 // if(cnt[i*2]==-1 || cnt[i*2+1]==-1) 113 // 114 // cnt[i]=-1; 115 // 116 // else if(cnt[i*2] != cnt[i*2+1]) 117 // 118 // cnt[i]=-1; 119 // 120 // else 121 // 122 // cnt[i]=cnt[i*2]; 123 // 124 // sum[i]=sum[i*2]+sum[i*2+1]; 125 // 126 //} 127 128 //void build(int i,int l,int r) 129 // 130 //{ 131 // 132 // if(l==r) 133 // 134 // { 135 // 136 // cnt[i]=0; 137 // 138 // sum[i]=0.0; 139 // 140 // return ; 141 // 142 // } 143 // 144 // int m=(l+r)/2; 145 // 146 // build(lson); 147 // 148 // build(rson); 149 // 150 // PushUp(i,l,r); 151 // 152 //} 153 // 154 //void update(int ql,int qr,int v,int i,int l,int r) 155 // 156 //{ 157 // 158 // if(ql<=l && r<=qr) 159 // 160 // { 161 // 162 // if(cnt[i]!=-1) 163 // 164 // { 165 // 166 // cnt[i]+=v; 167 // 168 // sum[i] = (cnt[i]? (w[r+1]-w[l]):0); 169 // 170 // return ; 171 // 172 // } 173 // 174 // } 175 // 176 // pushdown(i,l,r); 177 // 178 // int m=(l+r)/2; 179 // 180 // if(ql<=m) update(ql,qr,v,lson); 181 // 182 // if(m<qr) update(ql,qr,v,rson); 183 // 184 // pushup(i,l,r); 185 // 186 //} 187 // 188 //int searchs(double key,int n,double d[]) 189 // 190 //{ 191 // 192 // int l=1,r=n; 193 // 194 // while(r>=l) 195 // 196 // { 197 // 198 // int m=(r+l)/2; 199 // 200 // if(d[m]==key) 201 // 202 // return m; 203 // 204 // else if(d[m]>key) 205 // 206 // r=m-1; 207 // 208 // else 209 // 210 // l=m+1; 211 // 212 // } 213 // 214 // return -1; 215 // 216 //} 217 int main() 218 { 219 int n,k=0; 220 while(~scanf("%d",&n) && n) 221 { 222 int ans1=0,ans2=0; 223 for(int i=1;i<=n;++i) 224 { 225 double x1,y1,x2,y2; 226 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 227 w[++ans1]=x1; 228 w[++ans1]=x2; 229 tree[++ans2]=trees(x1,x2,y1,1); 230 tree[++ans2]=trees(x1,x2,y2,-1); 231 } 232 sort(w+1,w+1+ans1); 233 sort(tree+1,tree+1+ans2); 234 int ans=1; 235 for(int i=2;i<=ans1;++i) 236 { 237 if(w[i]!=w[i-1]) 238 { 239 w[++ans]=w[i]; 240 } 241 } 242 build(1,1,ans-1); 243 double ret=0.0; 244 for(int i=1;i<ans2;++i) 245 { 246 int l=searchs(1,ans,tree[i].l); 247 int r=searchs(1,ans,tree[i].r)-1; 248 //printf("%d %d %lf %lf\n",l,r,tree[i].l,tree[i].r); 249 if(l<=r) update(l,r,tree[i].d,1,1,ans-1); 250 ret+=sum[1]*(tree[i+1].h-tree[i].h); 251 //printf("%lf %lf %lf\n",sum[1],tree[i+1].h,tree[i].h); 252 } 253 printf("Test case #%d\nTotal explored area: %.2lf\n\n",++k,ret); 254 } 255 return 0; 256 }
例题: 二、覆盖的面积 HDU - 1255(重叠两次的面积)
题意:
给你一些矩形,让你求被覆盖至少两次区域的面积
题解:
和之前那个差不多,具体见代码
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 #define lch(i) ((i)<<1) 7 #define rch(i) ((i)<<1|1) 8 const int maxn=2005; 9 double w[maxn]; 10 struct shudui 11 { 12 double l,r,h; 13 int d; 14 shudui(){} 15 shudui(double a,double b,double c,int d): l(a),r(b),h(c),d(d){} 16 bool operator < (const shudui q)const 17 { 18 return h<q.h; 19 } 20 }v[maxn]; 21 struct trees 22 { 23 int l,r,m,cnt; 24 double s,ss; 25 }tree[maxn<<2]; 26 int n; 27 void build(int l,int r,int rt) 28 { 29 tree[rt].l=l; 30 tree[rt].r=r; 31 int m=(l+r)>>1; 32 tree[rt].m=m; 33 tree[rt].s=tree[rt].ss=tree[rt].cnt=0; 34 if(l==r) 35 { 36 return; 37 } 38 build(l,m,rt<<1); 39 build(m+1,r,rt<<1|1); 40 } 41 void pushup(int rt) //这种方法cnt是不会为负值的 42 { 43 if(tree[rt].cnt) 44 { 45 tree[rt].s=w[tree[rt].r+1]-w[tree[rt].l]; 46 } 47 else if(tree[rt].l==tree[rt].r) 48 tree[rt].s=0; 49 else 50 tree[rt].s=tree[rt<<1].s+tree[rt<<1|1].s; 51 if(tree[rt].cnt>1) 52 tree[rt].ss=w[tree[rt].r+1]-w[tree[rt].l]; 53 else if(tree[rt].l==tree[rt].r) 54 tree[rt].ss=0; 55 else if(tree[rt].cnt==1) 56 { 57 tree[rt].ss=tree[rt<<1].s+tree[rt<<1|1].s; 58 } 59 else tree[rt].ss=tree[rt<<1].ss+tree[rt<<1|1].ss; 60 } 61 void update(int L,int R,int C,int rt) 62 { 63 if(tree[rt].l==L && tree[rt].r==R) 64 { 65 tree[rt].cnt+=C; //这种方法cnt不往下传也不往上传 66 pushup(rt); 67 return; 68 } 69 int m=tree[rt].m; 70 if(R<=m) update(L,R,C,rt<<1); 71 else if(m<L) update(L,R,C,rt<<1|1); 72 else 73 { 74 update(L,m,C,rt<<1); 75 update(m+1,R,C,rt<<1|1); 76 } 77 pushup(rt); 78 } 79 //void cal(int rt) 80 //{ 81 // if(tree[rt].cnt) 82 // tree[rt].s = w[tree[rt].r+1] - w[tree[rt].l]; 83 // else if(tree[rt].l == tree[rt].r) 84 // tree[rt].s=0; 85 // else 86 // tree[rt].s = tree[lch(rt)].s + tree[rch(rt)].s; 87 ///**************************************************/ 88 // if(tree[rt].cnt > 1) 89 // tree[rt].ss = w[tree[rt].r+1] - w[tree[rt].l]; 90 // else if(tree[rt].l == tree[rt].r) 91 // tree[rt].ss = 0; 92 // else if(tree[rt].cnt == 1) 93 // tree[rt].ss = tree[lch(rt)].s + tree[rch(rt)].s; 94 // else 95 // tree[rt].ss = tree[lch(rt)].ss + tree[rch(rt)].ss; 96 //} 97 // 98 //void update(int l , int r ,int v ,int rt) 99 //{ 100 // if(tree[rt].l==l && tree[rt].r==r) 101 // { 102 // tree[rt].cnt += v; 103 // cal(rt); 104 // return ; 105 // } 106 // int mid=tree[rt].m; 107 // if(r<=mid) update(l,r,v,lch(rt)); 108 // else if(l>mid) update(l,r,v,rch(rt)); 109 // else 110 // { 111 // update(l,mid,v,lch(rt)); 112 // update(mid+1,r,v,rch(rt)); 113 // } 114 // cal(rt); 115 //} 116 int searchs(int l,int r,double x) 117 { 118 int m; 119 while(l<=r) 120 { 121 m=(l+r)>>1; 122 if(w[m]>x) r=m-1; 123 else if(w[m]<x) l=m+1; 124 else break; 125 } 126 return m; 127 } 128 //int searchs(int low ,int high,double key) 129 //{ 130 // while(low <= high) 131 // { 132 // int mid=(low+high)>>1; 133 // if(w[mid] == key) 134 // return mid; 135 // else if(w[mid] < key) 136 // low=mid+1; 137 // else 138 // high=mid-1; 139 // } 140 // return -1; 141 //} 142 int main() 143 { 144 int t; 145 scanf("%d",&t); 146 while(t--) 147 { 148 scanf("%d",&n); 149 int ans1=0,ans2=0; 150 for(int i=1;i<=n;++i) 151 { 152 double x1,y1,x2,y2; 153 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 154 w[++ans1]=x1; 155 w[++ans1]=x2; 156 v[++ans2]=shudui(x1,x2,y1,1); 157 v[++ans2]=shudui(x1,x2,y2,-1); 158 } 159 sort(w+1,w+1+ans1); 160 sort(v+1,v+1+ans2); 161 int k=1; 162 for(int i=2;i<=ans1;++i) 163 { 164 if(w[i]!=w[i-1]) 165 w[++k]=w[i]; 166 } 167 build(1,k-1,1); 168 double ret=0; 169 for(int i=1;i<ans2;++i) 170 { 171 int l=searchs(1,k,v[i].l); 172 int r=searchs(1,k,v[i].r)-1; //不知道什么时候出现一个k-1 173 if(l<=r) 174 //printf("%d %d %lf %lf\n",l,r,v[i].l,v[i].r); 175 update(l,r,v[i].d,1); 176 ret+=tree[1].ss*(v[i+1].h-v[i].h); 177 } 178 printf("%.2lf\n",ret); 179 } 180 return 0; 181 } 182 //int main() 183 //{ 184 // int T; 185 // scanf("%d",&T); 186 // while(T--) 187 // { 188 // scanf("%d",&n); 189 // int i,k; 190 // for(i=0,k=0; i<n; i++,k+=2) 191 // { 192 // double x1,y1,x2,y2; 193 // scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 194 // w[k]=x1; w[k+1]=x2; 195 // v[k].l=x1; v[k].r=x2; v[k].h=y1; v[k].d=1; 196 // v[k+1].l=x1; v[k+1].r=x2; v[k+1].h=y2; v[k+1].d=-1; 197 // } 198 // sort(w,w+k); 199 // sort(v,v+k); 200 // int m=1; 201 // for(i=1; i<k; i++) 202 // if(w[i]!=w[i-1]) 203 // w[m++]=w[i]; 204 // 205 // build(0,m-1,1); 206 // double res=0; 207 // for(i=0; i<k-1; i++) 208 // { 209 // int l=searchs(0,m-1,v[i].l); 210 // int r=searchs(0,m-1,v[i].r)-1; 211 // //printf("%d %d\n",l,r); 212 // update(l,r,v[i].d,1); 213 // res += tree[1].ss*(v[i+1].h - v[i].h); 214 // } 215 // printf("%.2lf\n",res); 216 // } 217 // return 0; 218 //}