线段树扫描线(一、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 //}
线段树扫描线(一、Atlantis HDU - 1542(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))的更多相关文章
- 线段树 扫描线 L - Atlantis HDU - 1542 M - City Horizon POJ - 3277 N - Paint the Wall HDU - 1543
学习博客推荐——线段树+扫描线(有关扫描线的理解) 我觉得要注意的几点 1 我的模板线段树的叶子节点存的都是 x[L]~x[L+1] 2 如果没有必要这个lazy 标志是可以不下传的 也就省了一个pu ...
- HDU 1542 - Atlantis - [线段树+扫描线]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...
- hdu 1542 Atlantis (线段树扫描线)
大意: 求矩形面积并. 枚举$x$坐标, 线段树维护$[y_1,y_2]$内的边是否被覆盖, 线段树维护边时需要将每条边挂在左端点上. #include <iostream> #inclu ...
- 覆盖的面积 HDU - 1255 (线段树-扫描线)模板提
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1& ...
- hdu1542 Atlantis (线段树+扫描线+离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- HDU 1828“Picture”(线段树+扫描线求矩形周长并)
传送门 •参考资料 [1]:算法总结:[线段树+扫描线]&矩形覆盖求面积/周长问题(HDU 1542/HDU 1828) •题意 给你 n 个矩形,求矩形并的周长: •题解1(两次扫描线) 周 ...
- hdu 1828 线段树扫描线(周长)
Picture Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞
看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...
- hdu 4052 线段树扫描线、奇特处理
Adding New Machine Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
随机推荐
- 一文带你学会AQS和并发工具类的关系
1. 存在的意义 AQS(AbstractQueuedSynchronizer)是JAVA中众多锁以及并发工具的基础,其底层采用乐观锁,大量使用了CAS操作, 并且在冲突时,采用自旋方式重试,以实 ...
- 【Oracle】dump函数用法
Oracle dump函数的用法 一.函数标准格式: DUMP(expr[,return_fmt[,start_position][,length]]) 基本参数时4个,最少可以填的参数是0个.当完全 ...
- RSA共模攻击
在安恒月赛中碰到一道密码学方向的ctf题 附上源码 from flag import flag from Crypto.Util.number import * p=getPrime(1024) q= ...
- linux下安装nacos
一.安装 1.下载安装包: https://github.com/alibaba/nacos/releases 2.解压 : tar -xzvf nacos-server-1.2.1.tar.gz 3 ...
- uni-app开发经验分享十六:发布android版App的详细过程
开发环境 1. Android Studio下载地址:Android Studio官网 OR Android Studio中文社区 2. HBuilderX(开发工具) 3. App离线SDK下载:最 ...
- CSS3+JS完美实现放大镜模式
最近看到一篇讲放大镜的文章,实践后感觉效果非常好,这里分享给大家. 效果如下: 其实现核心: CSS函数,如:calc() -- 动态计算:var() -- 使用自定义变量 CSS伪元素:::befo ...
- spark开窗函数
源文件内容示例: http://bigdata.beiwang.cn/laoli http://bigdata.beiwang.cn/laoli http://bigdata.beiwang.cn/h ...
- MySQL调优性能监控之performance schema
一.performance_schema的介绍 performance:性能 schema:图(表)示,以大纲或模型的形式表示计划或理论. MySQL的performance schema 用于监控M ...
- 为什么MySQL索引使用B+树
为什么MySQL索引使用B+树 聚簇索引与非聚簇索引 不同的存储引擎,数据文件和索引文件位置是不同的,但是都是在磁盘上而不是内存上,根据索引文件.数据文件是否放在一起而有了分类: 聚簇索引:数据文件和 ...
- 监听套接字描述字 已连接套接字描述字 和打电话的情形非常不一样的地方 完成了 TCP 三次握手,操作系统内核就为这个客户生成一个已连接套接字
1. accept: 电话铃响起了-- 当客户端的连接请求到达时,服务器端应答成功,连接建立,这个时候操作系统内核需要把这个事件通知到应用程序,并让应用程序感知到这个连接.这个过程,就好比电信运营商完 ...