Gym101611J 未被三角形覆盖的点

题意:w*h的平面中,给出n个三角形,且三角形面积总和不超过w*h。求任意一个未被三角形覆盖的点。

w,h<=10000, n<=100000, 坐标均为整数。

首先因为面积覆盖不满,这样的点必然存在。但是这里n非常大,如果用常规计算几何方法仅计算线段相交已经O(n^2)级别,而且后续也十分复杂,并不可做。因此考虑一条竖直扫描线,以扫到三角形段的长度总和(重复算多次)得到一个函数y=f(x)。如果对斜率求前缀和,在线段端点处更新,容易在扫描中计算出任意位置的函数值。

显然该函数必有一点x0的处函数值比h小,所以在这个点未被覆盖满,必然有解。考虑如何找到这样的x0:一个重要的观察是,因为坐标均为整点,所以函数f(x)在(n,n+1)闭区间中必为线性的。于是(n,n+1)区间函数的面积<h等价于该区间中点值小于h。因此枚举中点就可以找到x0。

找到x0后就比较方便了。对x=x0位置处被三角形覆盖的竖直区间端点排序,找到未被覆盖的区间即可。

  1. /*
  2. Author: fffasttime
  3. Date: 2019/09/21 13:10
  4.  */
  5. #include <bits/stdc++.h>
  6. using namespace std;
  7. typedef long long ll;
  8. #define inc(i,n) for (int i=0;i<n;i++)
  9. const int N=100010;
  10. typedef double db;
  11. db sk[N],sh[N];
  12. const db eps=1e-12;
  13. struct Line{
  14. 	db x1,y1,x2,y2; int t;
  15. 	db at(db x)const{
  16. 		return y1+(y2-y1)*((x-x1)/(x2-x1));
  17. 	}
  18. }line[N<<2],li2[N<<2];
  19. int linc;
  20. void added(int x1, int y1, int x2, int y2){
  21. 		if (x1==x2) return;
  22. 		db k=(db)(y2-y1)/(x2-x1);
  23. 		sk[x1]-=k;
  24. 		sk[x2]+=k;
  25. 		sh[x1]-=y1;
  26. 		sh[x2]+=y2;
  27. 		if (x1<x2)
  28. 		line[linc++]={x1,y1,x2,y2,1};
  29. 		else
  30. 		line[linc++]={x2,y2,x1,y1,-1};
  31. }
  32. int main(){
  33. 	int n,w,h;
  34. 	cin>>n>>w>>h;
  35. 	for (int i=0;i<n;i++){
  36. 		int x1,y1,x2,y2,x3,y3;
  37. 		scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3);
  38. 		if (x1*y2-x2*y1+x2*y3-x3*y2+x3*y1-x1*y3<0)
  39. 			swap(x2,x3), swap(y2,y3);
  40. 		added(x1,y1,x2,y2);
  41. 		added(x2,y2,x3,y3);
  42. 		added(x3,y3,x1,y1);
  43. 	}
  44. 	db ny=0,x0=0,ssy=0,ssk=0;
  45. 	for (int i=0;i<w;i++){
  46. 		x0=i+0.5;
  47. 		ssk+=sk[i];
  48. 		ny+=sh[i]+ssk*0.5;
  49. 		if (ny<h-1e-5){
  50. 			break;
  51. 		}
  52. 		ny+=ssk*0.5;
  53. 	}
  54. 	int scs=1; db lay=0, dif=0, ansy;
  55. 	linc=0;
  56. 	for (int i=0;i<3*n;i++)
  57. 		if (line[i].x1<x0 && line[i].x2>x0)
  58. 			li2[linc++]=line[i];	
  59. 	li2[linc++]={0,0,w,0,-1};
  60. 	li2[linc++]={w,h,0,h,1};
  61. 	sort(li2,li2+linc,[&](const Line &a, const Line &b){return a.at(x0)<b.at(x0);});
  62. 	for (int i=0;i<linc;i++){
  63. 		db y=li2[i].at(x0);
  64. 		if (scs==0 && y-lay>dif){
  65. 			dif=y-lay;
  66. 			ansy=(lay+y)/2;
  67. 		}
  68. 		scs+=li2[i].t;
  69. 		lay=y;
  70. 	}
  71. 	printf("%.9f %.9f\n",x0,ansy);
  72. 	return 0;
  73. }

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注