|
1 |
| -#include<bits/stdc++.h> |
| 1 | +#include <iostream> |
| 2 | +#include <vector> |
| 3 | +#include <algorithm> |
| 4 | +#include <cmath> |
2 | 5 |
|
3 | 6 | using namespace std;
|
4 | 7 |
|
5 |
| -struct vector2{ |
6 |
| - double x, y; |
| 8 | +typedef long long ll; |
7 | 9 |
|
8 |
| - vector2() { } |
| 10 | +struct Point |
| 11 | +{ |
| 12 | + int x, y; |
9 | 13 |
|
10 |
| - vector2(double _x, double _y): x(_x), y(_y) { } |
| 14 | + Point() {} |
11 | 15 |
|
12 |
| - double cross(const vector2& v) const { |
13 |
| - return x * v.y - y * v.x; |
| 16 | + Point(Point p1, Point p2) |
| 17 | + { |
| 18 | + x = p2.x - p1.x; |
| 19 | + y = p2.y - p1.y; |
14 | 20 | }
|
| 21 | +} P[200002]; |
15 | 22 |
|
16 |
| - double square_distance(const vector2& v) { |
17 |
| - return pow(x - v.x, 2) + pow(y - v.y, 2); |
18 |
| - } |
19 |
| - |
20 |
| - vector2 operator-(vector2 v) const{ |
21 |
| - return vector2(x - v.x, y - v.y); |
22 |
| - } |
23 |
| -}; |
| 23 | +typedef Point Vector; |
| 24 | +int T, N; |
| 25 | +Point base; |
| 26 | +vector<Point> hull; |
24 | 27 |
|
25 |
| -//positive when b is ccw to a |
26 |
| -double ccw(vector2 a, vector2 b){ |
27 |
| - return a.cross(b); |
| 28 | +bool operator==(Point& p1, Point& p2) |
| 29 | +{ |
| 30 | + return p1.x == p2.x && p1.y == p2.y; |
28 | 31 | }
|
29 | 32 |
|
30 |
| -double ccw(vector2 p, vector2 a, vector2 b){ |
31 |
| - return ccw(a - p, b - p); |
32 |
| -} |
| 33 | +bool comp1(Point p1, Point p2) |
| 34 | +{ |
| 35 | + if(p1 == base) return true; |
| 36 | + if(p2 == base) return false; |
| 37 | + p1.y -= base.y, p2.y -= base.y; |
| 38 | + p1.x -= base.x, p2.x -= base.x; |
33 | 39 |
|
34 |
| -int n; |
35 |
| -vector<vector2> P, st; |
36 |
| - |
37 |
| -bool comp1(vector2 v1, vector2 v2) { |
38 |
| - return v1.x == v2.x ? v1.y < v2.y : v1.x < v2.x; |
| 40 | + return atan2(p1.x, p1.y) > atan2(p2.x, p2.y); |
39 | 41 | }
|
40 | 42 |
|
41 |
| -bool comp2(vector2 v1, vector2 v2) { |
42 |
| - vector2 v = P[0]; |
43 |
| - |
44 |
| - double dir = ccw(v, v1, v2); |
45 |
| - |
46 |
| - return dir == 0 ? v.square_distance(v1) > v.square_distance(v2) : dir > 0; |
| 43 | +bool comp2(Point p1, Point p2) |
| 44 | +{ |
| 45 | + return p1.x == p2.x ? p1.y < p2.y : p1.x < p2.x; |
47 | 46 | }
|
48 | 47 |
|
49 |
| -struct PointCloud { |
50 |
| - void convexHull() { |
51 |
| - st.clear(); |
52 |
| - sort(P.begin(), P.end(), comp1); |
53 |
| - sort(P.begin() + 1, P.end(), comp2); |
54 |
| - |
55 |
| - st.push_back(P[0]); |
56 |
| - st.push_back(P[1]); |
57 |
| - st.push_back(P[2]); |
58 |
| - |
59 |
| - for(int i = 2; i <= n; i++) { |
60 |
| - vector2 p = P[i % n]; |
| 48 | +ll dist(Point p1, Point p2) |
| 49 | +{ |
| 50 | + return pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2); |
| 51 | +} |
61 | 52 |
|
62 |
| - while(st.size() >= 3) { |
63 |
| - int sz = st.size(); |
64 |
| - vector2 p1 = st[sz - 1], p2 = st[sz - 2]; |
| 53 | +int ccw(Vector v1, Vector v2) |
| 54 | +{ |
| 55 | + ll result = v1.x * v2.y - v2.x * v1.y; |
| 56 | + if(result > 0) return 1; |
| 57 | + else if(result < 0) return -1; |
| 58 | + else return 0; |
| 59 | +} |
65 | 60 |
|
66 |
| - if(ccw(p2, p1, p) <= 0) st.pop_back(); |
67 |
| - else break; |
| 61 | +int main() |
| 62 | +{ |
| 63 | + for(cin >> T; T > 0; T--) |
| 64 | + { |
| 65 | + hull.clear(); |
| 66 | + base.x = 1e9, base.y = 1e9; |
| 67 | + |
| 68 | + cin >> N; |
| 69 | + for(int i = 1; i <= N; i++) cin >> P[i].x >> P[i].y; |
| 70 | + |
| 71 | + sort(P + 1, P + N + 1, comp2); |
| 72 | + base = P[1]; |
| 73 | + sort(P + 2, P + N + 1, comp1); |
| 74 | + |
| 75 | + for(int i = 1; i <= N; i++) |
| 76 | + { |
| 77 | + while(hull.size() > 1) |
| 78 | + { |
| 79 | + int idx = hull.size(), dir; |
| 80 | + Vector v1(hull[idx - 2], hull[idx - 1]), v2(hull[idx - 1], P[i]); |
| 81 | + dir = ccw(v1, v2); |
| 82 | + |
| 83 | + if(dir >= 0) break; |
| 84 | + hull.pop_back(); |
68 | 85 | }
|
69 | 86 |
|
70 |
| - st.push_back(p); |
| 87 | + hull.push_back(P[i]); |
71 | 88 | }
|
72 |
| - } |
73 |
| - |
74 |
| - pair<vector2, vector2> farthestPoint() { |
75 |
| - vector2 v1, v2; |
76 |
| - long long mx = 0; |
77 |
| - int j = 1, sz = st.size(); |
78 | 89 |
|
79 |
| - if(sz - 1 <= 2) { |
80 |
| - return {st[0], st[1]}; |
81 |
| - } |
82 |
| - |
83 |
| - for(int i = 0; i < sz - 1; i++) { |
84 |
| - vector2 p1 = st[i], p2 = st[(i + 1) % (sz - 1)]; |
85 |
| - vector2 q1, q2, q3; |
86 |
| - |
87 |
| - while(1) { |
88 |
| - q1 = st[j], q2 = st[(j + 1) % (sz - 1)], q3 = st[(j + 2) % (sz - 1)]; |
89 |
| - vector2 p = p2 - p1, _q1 = q2 - q1, _q2 = q3 - q2; |
90 |
| - |
91 |
| - if((ccw(p, _q1) >= 0) ^ (ccw(p, _q2) >= 0)) break; |
92 |
| - j = (j + 1) % (sz - 1); |
93 |
| - } |
94 |
| - |
95 |
| - if(mx < p1.square_distance(q1)) { |
96 |
| - mx = p1.square_distance(q1); |
97 |
| - v1 = p1; |
98 |
| - v2 = q1; |
| 90 | + ll ans[3] = { 0, 0, 0 }; |
| 91 | + int idx1_1 = 0, idx2_1 = 1, sz = hull.size(); |
| 92 | + while(idx2_1 != 0) |
| 93 | + { |
| 94 | + ll d = dist(hull[idx1_1], hull[idx2_1]); |
| 95 | + if(ans[0] < d) |
| 96 | + { |
| 97 | + ans[0] = d; |
| 98 | + ans[1] = idx1_1, ans[2] = idx2_1; |
99 | 99 | }
|
100 | 100 |
|
101 |
| - if(mx < p1.square_distance(q2)) { |
102 |
| - mx = p1.square_distance(q2); |
103 |
| - v1 = p1; |
104 |
| - v2 = q2; |
105 |
| - } |
106 |
| - |
107 |
| - if(mx < p1.square_distance(q3)) { |
108 |
| - mx = p1.square_distance(q3); |
109 |
| - v1 = p1; |
110 |
| - v2 = q3; |
111 |
| - } |
112 |
| - } |
| 101 | + int dir, idx1_2 = (idx1_1 + sz - 1) % sz, idx2_2 = (idx2_1 + sz - 1) % sz; |
| 102 | + Vector v1(hull[idx1_2], hull[idx1_1]), v2(hull[idx2_2], hull[idx2_1]); |
| 103 | + dir = ccw(v1, v2); |
113 | 104 |
|
114 |
| - return {v1, v2}; |
115 |
| - } |
116 |
| -} T; |
117 |
| - |
118 |
| -int main(){ |
119 |
| - ios::sync_with_stdio(false); |
120 |
| - cin.tie(NULL); |
121 |
| - int t; |
122 |
| - |
123 |
| - for(cin >> t; t > 0; t--) { |
124 |
| - P.clear(); |
125 |
| - cin >> n; |
126 |
| - for(int i = 0; i < n; i++) { |
127 |
| - int x, y; |
128 |
| - cin >> x >> y; |
129 |
| - P.push_back(vector2(x, y)); |
| 105 | + if(dir >= 0) idx2_1 = (idx2_1 + 1) % sz; |
| 106 | + else idx1_1 = (idx1_1 + 1) % sz; |
130 | 107 | }
|
131 | 108 |
|
132 |
| - T.convexHull(); |
133 |
| - auto result = T.farthestPoint(); |
134 |
| - |
135 |
| - cout << (int)result.first.x << ' ' << (int)result.first.y << ' ' << (int)result.second.x << ' ' << (int)result.second.y << '\n'; |
| 109 | + cout << hull[ans[1]].x << ' ' << hull[ans[1]].y << ' ' << hull[ans[2]].x << ' ' << hull[ans[2]].y << '\n'; |
136 | 110 | }
|
137 | 111 | }
|
0 commit comments