题目大意:
以下所有的东西都在第一象限。
给出n个点,和m个以原点为顶点的三角形,对每一个三角形询问是否有点在三角形内。
1 <= n <= 100000
题解:
把三角形看成原点出去的两个向量。
首先一个点要在三角形内,一定要在这两个向量的夹角间,并且要在三角形另外两个顶点形成的直线下。
第一个限制非常好搞,只需要把所有点极角排序,那么合法的点就在一个区间内了。
对于这个区间内的点,建一个下凸壳,我们只需要取凸壳上的直线斜率最大且小于等于这个三角形另外两个端点形成直线的斜率的那条直线对应的两个端点判断即可。
为什么呢?
可以把这条三角形端点形成的直线旋转成x轴,然后我们知道下凸壳的直线斜率是递减的,旋转坐标系后斜率也是递增的。
凸壳在旋转坐标系以后可以理解为先向下走,再向上走,所以我们只需要找到向上走的那个临界点就是最低点了。
于是用线段树维护凸壳,查询时二分。
复杂度 O(n log n+qlog2n) O ( n l o g n + q l o g 2 n ) 。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define i0 i + i
#define i1 i + i + 1
using namespace std;
const int N = 1e5 + 5;
struct P {
int x, y;
P(int _x = 0, int _y = 0) {x = _x, y = _y;}
} a[N], b, c, t[N];
P operator -(P a, P b) {return P(a.x - b.x, a.y - b.y);}
ll operator ^(P a, P b) {return (ll) a.x * b.y - (ll) a.y * b.x;}
bool operator <(P a, P b) {return (a ^ b) > 0;}
int n, q, ans;
int st[N * 4], en[N * 4], d[N * 20], d0;
int pl, pr, z0;
void bl(int i, int x, int y) {
if(x == y) {
d[++ d0] = x;
st[i] = en[i] = d0;
return;
}
int m = x + y >> 1; bl(i0, x, m); bl(i1, m + 1, y);
st[i] = d0 + 1;
fo(j, st[i0], en[i0]) d[++ d0] = d[j];
fo(j, st[i1], en[i1]) {
while(d0 > st[i] && ((a[d[j]] - a[d[d0]]) ^ (a[d[d0]] - a[d[d0 - 1]])) <= 0) d0 --;
d[++ d0] = d[j];
}
en[i] = d0;
}
void fi(int i, int x, int y) {
if(y < pl || x > pr) return;
if(x >= pl && y <= pr) {
int p = st[i];
for(int l = st[i], r = en[i] - 1; l <= r; ) {
int m = l + r >> 1;
if(((c - b) ^ (a[d[m + 1]] - a[d[m]])) >= 0)
p = m, l = m + 1; else r = m - 1;
}
if(((c - b) ^ (a[d[p]] - b)) >= 0) ans = 1;
if(p < en[i] && ((c - b) ^ (a[d[p + 1]] - b)) >= 0) ans = 1;
if(p > st[i] && ((c - b) ^ (a[d[p - 1]] - b)) >= 0) ans = 1;
return;
}
int m = x + y >> 1; fi(i0, x, m); fi(i1, m + 1, y);
}
int main() {
scanf("%d %d", &n, &q);
fo(i, 1, n) scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1);
bl(1, 1, n);
fo(ii, 1, q) {
scanf("%d %d %d %d", &b.x, &b.y, &c.x, &c.y);
if(c < b) swap(b, c);
pl = lower_bound(a + 1, a + n + 1, b) - a, pr = upper_bound(a + 1, a + n + 1, c) - a - 1;
ans = 0; fi(1, 1, n);
putchar(ans ? 'Y' : 'N'); putchar('\n');
}
}