线段树扫描线(一、Atlantis HDU - 1542(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))

时间:2022-06-28 09:52:50

扫描线求周长: 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(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))

例题:一、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 //}