N (≤1001) 台電腦,坐標已知,通訊距離 ≤ d。操作兩類:
O p:修復電腦 p(激活)S p q:查詢 p、q 能否通訊(直接或間接)操作數 ≤ 300,000。輸出 "SUCCESS" 或 "FAIL"。
adj[i] 存與 i 距離 ≤ d 的電腦O p:激活 p,遍歷 adj[p],若鄰居已激活,union(p, 鄰居)S p q:若 p、q 均激活且 find(p) == find(q) → SUCCESS#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const int MAXN = 1005;
struct Computer {
int x, y;
bool active = false;
vector adj;
} pc[MAXN];
int fa[MAXN];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void unite(int x, int y) {
int fx = find(x), fy = find(y);
if (fx != fy) fa[fx] = fy;
}
double dist(int i, int j) {
double dx = pc[i].x - pc[j].x;
double dy = pc[i].y - pc[j].y;
return sqrt(dx*dx + dy*dy);
}
int main() {
int N; double d;
scanf("%d %lf", &N, &d);
for (int i = 1; i <= N; ++i) {
scanf("%d %d", &pc[i].x, &pc[i].y);
fa[i] = i;
}
// 預計算鄰接
for (int i = 1; i <= N; ++i)
for (int j = i+1; j <= N; ++j)
if (dist(i, j) <= d + 1e-8) { // 浮點誤差
pc[i].adj.push_back(j);
pc[j].adj.push_back(i);
}
char op;
while (scanf(" %c", &op) == 1) {
if (op == 'O') {
int p; scanf("%d", &p);
pc[p].active = true;
for (int nb : pc[p].adj)
if (pc[nb].active) unite(p, nb);
} else if (op == 'S') {
int p, q; scanf("%d %d", &p, &q);
if (pc[p].active && pc[q].active && find(p) == find(q))
puts("SUCCESS");
else
puts("FAIL");
}
}
return 0;
}
find 遞歸壓縮,近乎 O(1)1e-8 容差O:O(度數) ≤ O(N)S:O(α(N))此題是並查集維護動態圖連通性的標準範例,「激活節點並合併已激活鄰居」模式廣泛應用於網絡恢復、社交網絡動態連通等場景。