TIOJ 1631:[IOI 2006] 點連接遊戲
TIOJ 1631:[IOI 2006] 點連接遊戲
題目大意:有一個平面跟 $n_0$ 個綠點、$n_1$ 個紅點,$s$ 為座標最大值,保證 $(0, s), (s, s)$ 是綠點,$(0, 0), (s, 0)$ 是紅點,三點不共線,想要綠點們互相連接,紅點們互相連接,形成兩棵不相交的樹。
解法:考慮現在有兩個綠點、一個紅點圍起來的三角形,如果中間的區域沒有點,那就終止,如果中間的點都是同一個顏色,那就挑同顏色的點連邊,否則我們可以隨機挑一個紅點,連一條邊,然後就會變成三個小三角形,就可以繼續遞迴了。時間複雜度 $O(n\times\log(n))$。
$\text{Code:}$
#include <bits/stdc++.h>
#include "lib1631.h"
using namespace std;
using ll = long long;
struct T {
int c, x, y, id;
T() {}
T (int x, int y) : x (x), y (y) {}
T (int c, int x, int y, int id) : c (c), x (x), y (y), id (id) {}
T operator - (const T &v) const {
return T (x - v.x, y - v.y);
}
ll operator * (const T &v) const {
return 1ll * x * v.y - 1ll * y * v.x;
}
};
int n[2], s;
mt19937 seed (time (NULL));
inline int rnd (int l, int r) {
return uniform_int_distribution<int> (l, r) (seed);
}
inline bool inside (T p, T a, T b, T c) {
int cnt = 0;
cnt += (a - p) * (b - p) > 0;
cnt += (b - p) * (c - p) > 0;
cnt += (c - p) * (a - p) > 0;
return cnt == 0 || cnt == 3;
}
void divide (T p, T a, T b, vector<T> v) {
if (v.size() == 0) return;
int cnt[2] = {};
for (auto &[c, x, y, id] : v) cnt[c]++;
if (cnt[0] == 0 || cnt[1] == 0) {
for (T &vp : v) Report (vp.c, vp.id, p.c == vp.c ? p.id : a.id);
return;
}
vector<T> vc, vpa, vpb, vab;
for (T &vp : v) if (vp.c == p.c) vc.emplace_back (vp);
T np = vc[rnd (0, vc.size() - 1)];
Report (p.c, p.id, np.id);
for (T &vp : v) if (vp.c != np.c || vp.id != np.id) {
if (inside (vp, p, a, np)) vpa.emplace_back (vp);
else if (inside (vp, p, b, np)) vpb.emplace_back (vp);
else vab.emplace_back (vp);
}
divide (a, p, np, vpa);
divide (b, p, np, vpb);
divide (np, a, b, vab);
}
int main() {
Init (n[0], n[1]);
vector<T> v, vl, vr;
for (int c = 0; c <= 1; c++) for (int i = 1; i <= n[c]; i++) {
int x, y;
Get (c, x, y);
v.emplace_back (c, x, y, i);
s = max ({s, x, y});
}
T p[4];
int pos = 0;
for (auto &[c, x, y, id] : v) {
if ((x == 0 || x == s) && (y == 0 || y == s)) {
p[pos++] = T (c, x, y, id);
} else {
if (inside (T (x, y), T (0, 0), T (0, s), T (s, s))) vl.emplace_back (c, x, y, id);
else vr.emplace_back (c, x, y, id);
}
}
Report (0, p[0].id, p[1].id);
divide (p[2], p[0], p[1], vl);
Report (1, p[2].id, p[3].id);
divide (p[1], p[2], p[3], vr);
Finish();
}
我的分享就到這裡結束了,如果喜歡我的 $\text{Blog}$,歡迎追蹤!
留言
張貼留言