Gym 100883J palprime(二分判断点在凸包里)
题意:判断一堆小点有多少个在任意三个大点构成的三角形里面。
思路:其实就是判断点在不在凸包里面,判断的话可以使用二分来判断,就是判断该点在凸包的哪两个点和起点的连线之间。
代码:
1 /** @xigua */ 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 #include<stack> 8 #include<cstring> 9 #include<queue> 10 #include<set> 11 #include<string> 12 #include<map> 13 #include<climits> 14 #define PI acos(-1) 15 using namespace std; 16 typedef long long ll; 17 typedef double db; 18 const int maxn = 5e4 + 5; 19 const int mod = (1 << 31) - 1; 20 const int INF = 1e8 + 5; 21 const ll inf = 1e15 + 5; 22 const db eps = 1e-6; 23 24 struct Node { 25 ll x, y, id; 26 } po[maxn]; 27 int n; 28 int flag; 29 30 bool cmp(const Node &a, const Node &b) { 31 if (a.x == b.x) return a.y < b.y; 32 return a.x < b.x; 33 } 34 35 ll mul(ll x1, ll x2, ll y1, ll y2) { 36 return x1 * y2 - x2 * y1; 37 } 38 Node S[maxn]; 39 int top; 40 41 void ch(Node cur) { 42 while (top > flag) { 43 Node po1 = S[top]; 44 Node po2 = S[top-1]; 45 ll x1 = po1.x - po2.x, y1 = po1.y - po2.y; 46 ll x2 = cur.x - po2.x, y2 = cur.y - po2.y; 47 if (mul(x1, x2, y1, y2) >= 0) { 48 top--; 49 } 50 else break; 51 } 52 S[++top] = cur; 53 } 54 55 int ok(int mid, ll x, ll y) { 56 ll x1 = S[mid].x - S[1].x, y1 = S[mid].y - S[1].y; 57 ll x2 = x - S[1].x, y2 = y - S[1].y; 58 ll tmp = mul(x1, x2, y1, y2); 59 if (tmp > 0) return 1; 60 if (tmp == 0) return 2; 61 return 0; 62 } 63 64 void solve() { 65 while (cin >> n) { 66 for (int i = 1; i <= n; i++) { 67 scanf("%I64d%I64d", &po[i].x, &po[i].y); 68 po[i].id = i; 69 } 70 sort(po+1, po+1+n, cmp); 71 top = 0; 72 flag = 1; 73 for (int i = 1; i <= n; i++) { 74 ch(po[i]); 75 } 76 flag = top; 77 for (int i = n-1; i >= 1; i--) { 78 ch(po[i]); 79 } 80 top--; 81 int q, ans = 0; cin >> q; 82 Node tmp[maxn]; 83 for (int i = 1; i <= top; i++) 84 tmp[i] = S[i]; 85 for (int i = 2; i <= top; i++) 86 S[i] = tmp[top-i+2]; 87 while (q--) { 88 ll x, y; 89 scanf("%I64d%I64d", &x, &y); 90 int l = 2, r = top; //二分上界和下界 91 while (l < r) { 92 int mid = l + r + 1 >> 1; 93 if (ok(mid, x, y)) //在当前这条线之上 94 l = mid; 95 else r = mid - 1; 96 } 97 if (l == top) { //在上界需要特殊判断 98 if (ok(l, x, y) == 2) { 99 ll a = x - S[1].x, b = y - S[1].y; 100 ll dis1 = a * a + b * b; 101 a = S[l].x - S[1].x, b = S[l].y - S[1].y; 102 ll dis2 = a * a + b * b; 103 if (dis1 <= dis2) ans++; 104 } 105 continue; 106 } 107 Node xx[5]; 108 xx[1] = S[1], xx[2] = S[l], xx[3] = S[l+1], xx[4] = S[1]; 109 ll are1 = 0; 110 for (int i = 1; i <= 3; i++) { 111 ll x1 = xx[i].x - x, y1 = xx[i].y - y; 112 ll x2 = xx[i+1].x - x, y2 = xx[i+1].y - y; 113 ll tmp = mul(x1, x2, y1, y2); 114 if (tmp < 0) tmp = -tmp; 115 are1 += tmp; 116 } 117 ll x1 = xx[2].x - xx[1].x, y1 = xx[2].y - xx[1].y; 118 ll x2 = xx[3].x - xx[1].x, y2 = xx[3].y - xx[1].y; 119 ll are2 = mul(x1, x2, y1, y2); 120 //if (are1 < 0) are1 = -are1; 121 if (are2 < 0) are2 = -are2; 122 if (are2 == are1) ans++; //通过面积来判断,are1代表的是加上该点的 123 } 124 cout << ans << endl; 125 } 126 } 127 128 int main() { 129 //cin.sync_with_stdio(false); 130 //freopen("in.txt", "r", stdin); 131 //freopen("isharp.out", "w", stdout); 132 int t = 1; //cin >> t; 133 134 while (t--) { 135 solve(); 136 } 137 return 0; 138 }