HDU-1255 覆盖的面积(线段树扫描线+离散化+改进后超快的算法)

淡淡的烟草味﹌ 2022-06-10 10:40 251阅读 0赞

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.

d1adc6253c233d9968f03fe1d872f86d_v_1502769328

Input

输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

注意:本题的输入数据较多,推荐使用scanf读入数据.

Output

对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.

Sample Input

  1. 2
  2. 5
  3. 1 1 4 2
  4. 1 3 3 7
  5. 2 1.5 5 4.5
  6. 3.5 1.25 7.5 4
  7. 6 3 10 7
  8. 3
  9. 0 0 1 1
  10. 1 0 2 1
  11. 2 0 3 1

Sample Output

  1. 7.63
  2. 0.00

题解:

这题我之前用区间单点暴力的做法1500ms过的,很不甘心,今天上午研究了几个人的写法,后来发现有一种很巧妙的思想,就是我们在扫描线模板的基础上,每一个节点保存的数据为2个,一个为覆盖一次的长度,另一个为覆盖两次以上的长度,那么我们每次更新两个长度,先更新len1,如果完全覆盖就赋全值,如果为一个点就为0,如果都不是就为子区间len1长度和,然后更新len2,如果覆盖两次赋权值,为点就为0,覆盖一次就改成子区间的len1和,其余情况为子区间len2和,然后其他和基本扫描线做法是一样了,还有就是答案依然要加上一个玄学控制精度的eps,这个做法速度可以达到190ms左右速度

附上之前的比较暴力的做法博客:http://blog.csdn.net/qq_37497322/article/details/77255966

代码:

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<stdio.h>
  5. #include<math.h>
  6. #include<string>
  7. #include<stdio.h>
  8. #include<queue>
  9. #include<stack>
  10. #include<map>
  11. #include<vector>
  12. #include<deque>
  13. using namespace std;
  14. #define lson k*2
  15. #define rson k*2+1
  16. #define M (t[k].l+t[k].r)/2
  17. #define INF 1008611111
  18. #define ll long long
  19. #define eps 1e-15
  20. struct node
  21. {
  22. int l,r;
  23. double len1;//覆盖一次的长度
  24. double len2;//覆盖两次长度
  25. int v;//记录覆盖次数
  26. }t[2005*4];
  27. double xx[2005];//离散化后的数组
  28. void Build(int l,int r,int k)
  29. {
  30. t[k].l=l;
  31. t[k].r=r;
  32. t[k].len1=0;
  33. t[k].len2=0;
  34. t[k].v=0;
  35. if(l==r)
  36. return;
  37. int mid=M;
  38. Build(l,mid,lson);
  39. Build(mid+1,r,rson);
  40. }
  41. void pushup1(int k)//更新len1
  42. {
  43. if(t[k].v>0)
  44. {
  45. t[k].len1=xx[t[k].r+1]-xx[t[k].l];
  46. return;
  47. }
  48. else if(t[k].l==t[k].r)
  49. {
  50. t[k].len1=0;
  51. }
  52. else
  53. {
  54. t[k].len1=t[lson].len1+t[rson].len1;
  55. }
  56. }
  57. void pushup2(int k)//更新len2
  58. {
  59. if(t[k].v>1)
  60. {
  61. t[k].len2=xx[t[k].r+1]-xx[t[k].l];
  62. return;
  63. }
  64. if(t[k].l==t[k].r)
  65. {
  66. t[k].len2=0;
  67. }
  68. else if(t[k].v==1)
  69. {
  70. t[k].len2=t[lson].len1+t[rson].len1;
  71. }
  72. else
  73. {
  74. t[k].len2=t[lson].len2+t[rson].len2;
  75. }
  76. }
  77. void update(int l,int r,int k,int d)
  78. {
  79. if(l==t[k].l&&t[k].r==r)
  80. {
  81. t[k].v+=d;
  82. pushup1(k);
  83. pushup2(k);
  84. return;
  85. }
  86. int mid=M;
  87. if(r<=mid)
  88. update(l,r,lson,d);
  89. else if(l>mid)
  90. update(l,r,rson,d);
  91. else
  92. {
  93. update(l,mid,lson,d);
  94. update(mid+1,r,rson,d);
  95. }
  96. pushup1(k);
  97. pushup2(k);
  98. }
  99. struct edge//存扫描线
  100. {
  101. double l,r;
  102. double h;
  103. int d;//存扫描线性质,1为下底,-1为上底
  104. }a[2005];
  105. int cmp(edge x,edge y)//按高度从小到大排序
  106. {
  107. if(x.h!=y.h)
  108. return x.h<y.h;
  109. return x.d<y.d;
  110. }
  111. int main()
  112. {
  113. int i,j,k,n,tot,l,r,test,ans;
  114. double x1,x2,y1,y2;
  115. scanf("%d",&test);
  116. while(test--)
  117. {
  118. scanf("%d",&n);
  119. tot=0;
  120. for(i=0;i<n;i++)
  121. {
  122. scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
  123. a[tot].l=x1;
  124. a[tot].r=x2;
  125. a[tot].h=y1;
  126. a[tot].d=1;
  127. a[tot+1].l=x1;
  128. a[tot+1].r=x2;
  129. a[tot+1].h=y2;
  130. a[tot+1].d=-1;
  131. xx[tot]=x1;
  132. xx[tot+1]=x2;
  133. tot+=2;
  134. }
  135. sort(xx,xx+tot);
  136. sort(a,a+tot,cmp);
  137. ans=unique(xx,xx+tot)-xx;//离散化去重
  138. Build(0,ans-1,1);
  139. double s=0.0;
  140. int l=lower_bound(xx,xx+ans,a[0].l)-xx;
  141. int r=lower_bound(xx,xx+ans,a[0].r)-xx-1;
  142. update(l,r,1,a[0].d);
  143. for(i=1;i<tot;i++)
  144. {
  145. s+=(t[1].len2*(a[i].h-a[i-1].h));
  146. l=lower_bound(xx,xx+ans,a[i].l)-xx;
  147. r=lower_bound(xx,xx+ans,a[i].r)-xx-1;
  148. update(l,r,1,a[i].d);
  149. }
  150. printf("%.2lf\n",s+eps);//玄学
  151. }
  152. return 0;
  153. }

发表评论

表情:
评论列表 (有 0 条评论,251人围观)

还没有评论,来说两句吧...

相关阅读