题意:在一个巨大的三维网格空间中建造 n 条垂直坐标系的隧道,q 个询问,询问两点之间是否可以通过隧道到达。
分析:考虑使用并查集维护,但是如何合并两条隧道较难处理,因为这个网格空间的量级是 1e6 的,我们不可能每次都将整条隧道中的点合并。假设建了一条 (x,y,−1) 的隧道,如下图加粗蓝色柱体:
题解链接
总结:
写完这个题给我的体会就是我缺少三维空间的想象能力。
然后还有 并查集可以写一个 struct ,这样就会很方便。
还有一个匿名函数,写在主程序里面,也很方便。
#include<bits/stdc++.h>
using namespace std;
const int M = 1e6+20;
const int N = 6e5+100;
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,m;
struct node{
int x,y,z;
node(){}
node(int _x, int _y, int _z) : x(_x), y(_y),z(_z){}
bool operator < (node A) const {
if (x ^ A.x) return x < A.x;
if (y ^ A.y) return y < A.y;
return z < A.z;
}
};
struct Disjoin{
int f[M];
void init(int n){
for (int i = 0; i <= n; ++i) f[i] = i;
}
int find(int k){
return f[k] == k ? k : f[k] = find(f[k]);
}
bool isSame(int x, int y) {return find(x) == find(y); }
int union_ver(int x, int y){
int xx = find(x), yy = find(y);
if (xx != yy) {
f[xx] = yy; return 1;
}
return 0;
}
}U;
int main(){
int T; scanf("%d",&T);
while(T--){
scanf("%d",&n);
U.init(M-10);
// xy xy 这个平面, 线是沿着 x 这个方向。
vector< set<int> >xy(M),yx(M),yz(M),zy(M),xz(M),zx(M);
map<node, int> mp;
int x,y,z;
for (int i = 0; i < n; ++i){
scanf("%d%d%d",&x,&y,&z);
if (x == -1){
xz[y].insert(i);
xy[z].insert(i);
} else if (y == -1){
yx[z].insert(i);
yz[x].insert(i);
} else {
zx[y].insert(i);
zy[x].insert(i);
}
mp[node(x,y,z)] = i;
}
for (auto it: mp){
node tp = it.first;
int id = it.second;
if (tp.x == -1){
for (auto y : {tp.y -1, tp.y, tp.y+1}){
for (auto i : zx[y]){
U.union_ver(i, id);
}
if (!zx[y].empty()) zx[y] = {*zx[y].begin()};
if (mp.count(node(-1,y,tp.z)))
U.union_ver(mp[node(-1,y,tp.z)], id);
}
for (auto z: {tp.z-1, tp.z, tp.z+1}){
for (auto i: yx[z]){
U.union_ver(i,id);
}
if (!yx[z].empty()) yx[z] = {*yx[z].begin()};
if (mp.count(node(-1,tp.y,z)))
U.union_ver(mp[node(-1,tp.y,z)], id);
}
} else if (tp.y == -1){
for (auto x : {tp.x-1, tp.x, tp.x+1}){
for (auto i : zy[x])
U.union_ver(i,id);
if (!zy[x].empty()) zy[x] = {*zy[x].begin()};
if (mp.count(node(x,-1,tp.z)))
U.union_ver(mp[node(x,-1,tp.z)], id);
}
for (auto z : {tp.z-1, tp.z, tp.z+1}){
for (auto i : xy[z])
U.union_ver(i, id);
if (!xy[z].empty()) xy[z] = {*xy[z].begin()};
if (mp.count(node(tp.x, -1, z)))
U.union_ver(mp[node(tp.x, -1, z)], id);
}
} else {
for (auto x : {tp.x-1, tp.x, tp.x+1}){
for (auto i : yz[x])
U.union_ver(i, id);
if (!yz[x].empty()) yz[x] = {*yz[x].begin()};
if (mp.count(node(x, tp.y, -1)))
U.union_ver(mp[node(x, tp.y, -1)], id);
}
for (auto y : {tp.y-1, tp.y, tp.y+1}){
for (auto i : xz[y])
U.union_ver(i, id);
if (!xz[y].empty()) xz[y] = {*xz[y].begin()};
if (mp.count(node(tp.x, y, -1)))
U.union_ver(mp[node(tp.x, y, -1)], id);
}
}
}
auto getId = [&](node p){
int x = p.x, y = p.y, z = p.z;
int id = -1;
if (mp.count(node(x,y,-1)))
id = mp[node(x,y,-1)];
if (mp.count(node(x,-1,z)))
id = mp[node(x,-1,z)];
if (mp.count(node(-1,y,z)))
id = mp[node(-1,y,z)];
return id;
};
int q; scanf("%d",&q);
for (int i = 1; i<= q; ++i){
node a,b;
scanf("%d%d%d%d%d%d",&a.x,&a.y,&a.z,&b.x,&b.y,&b.z);
if (U.isSame(getId(a), getId(b))) puts("YES");
else puts("NO");
}
}
return 0;
}
/*
1
6
-1 1 1
3 -1 2
1 5 -1
5 5 -1
-1 5 5
-1 5 9
6
1 1 1 6 1 1
8 1 1 3 2 2
1 1 1 5 5 5
1 5 5 5 5 9
1 5 10 10 1 1
1 5 9 5 5 9
*/