题目描述
给出一个凸多边形,多次询问某个点是否在这个凸多边形的内部,强制在线。
输入
第一行一个数n,接下来n行,每行两个整数x,y。输入按照逆时针顺序输入一个凸包。
接下来一个数m,最后有m行,第一行两个整数 x,y,表示第一个人的坐标。
对于第i个询问(i>=2) ,输入两个数dx,dy。
如果上一个人在房子内部,x[i]=x[i-1]+dx,y[i]=y[i-1]+dy。否则x[i]=x[i-1]-dx,y[i]=y[i-1]-dy。
n <= 100000, m <= 200000,输入保证所有人的坐标,房屋的坐标都在[-1e9,1e9]之内。
输出
输出一个数,在房子内部人的个数。
样例输入
4
-2 -2
2 -2
2 2
-2 2
3
5 5
4 4
0 3
样例输出
1
题解
计算几何的经典应用
固定一个点,将其它的点与它的连线按照极角排序,将多边形三角剖分。
然后查询一个点是否在多边形内部,首先与固定的点连线,找到极角的前驱后继,问题转化为判断是否在前驱后继以及固定点围成的三角形内。可以通过求面积的方法来判断。
然而我这个傻逼写了set。。。还选了最低的点。。。其实不必要的。。。
时间复杂度$O(nlog n)$
#include <set> #include <cmath> #include <cstdio> #include <utility> using namespace std; typedef pair<double , int> pr; set<pr> s; set<pr>::iterator it; double px[100010] , py[100010] , vx , vy = 1e10; inline double calc(double x1 , double y1 , double x2 , double y2) { return fabs(x1 * y2 - x2 * y1); } bool judge(double x , double y) { int p , q; it = s.lower_bound(pr(atan2(y - vy , x - vx) , 0)); if(it == s.end() || it == s.begin()) return 0; p = it->second , q = (--it)->second; return fabs(calc(px[p] - vx , py[p] - vy , px[q] - vx , py[q] - vy) - calc(px[p] - x , py[p] - y , px[q] - x , py[q] - y) - calc(px[p] - x , py[p] - y , vx - x , vy - y) - calc(px[q] - x , py[q] - y , vx - x , vy - y)) < 1e-8; } int main() { int n , m , i , last = 1 , ans = 0; double lx = 0 , ly = 0 , x , y; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) { scanf("%lf%lf" , &px[i] , &py[i]); if(vy > py[i]) vx = px[i] , vy = py[i]; } for(i = 1 ; i <= n ; i ++ ) s.insert(pr(atan2(py[i] - vy , px[i] - vx) , i)); scanf("%d" , &m); while(m -- ) { scanf("%lf%lf" , &x , &y); if(last) lx += x , ly += y; else lx -= x , ly -= y; last = judge(lx , ly) , ans += last; } printf("%d " , ans); return 0; }