题目链接:点我啊╭(╯^╰)╮
题目大意:
一个
n
∗
m
∗
h
n*m*h
n∗m∗h 的立方体
两个操作:
1
1
1
x
x
x
y
y
y
z
z
z 在这个立方体上标记一个点
2
2
2
x
x
x
y
y
y
z
z
z 求离这个点最近的标记点的曼哈顿距离
解题思路:
首先对于多个标记点,可以一次
O
(
n
m
h
)
O(nmh)
O(nmh) 的多源
B
F
S
BFS
BFS 处理到每个点的距离,这样查询是
O
(
1
)
O(1)
O(1) 的
假设已经标记了
K
K
K 个点,暴力求查询点的最近点是
O
(
K
)
O(K)
O(K) 的
考虑将两者结合起来,将标记点放到一个栈里,定期重构
B
F
S
BFS
BFS
设置阈值
E
E
E ,当标记点个数
K
<
E
K<E
K<E 时,采用暴力查询,
O
(
q
E
)
O(qE)
O(qE)
当标记点个数
K
>
=
E
K>=E
K>=E 时,重构一次
B
F
S
BFS
BFS ,
O
(
q
n
m
h
/
E
)
O(qnmh/E)
O(qnmh/E)
重构之后,相当于这个
K
K
K 个点已经更新到了答案之中,清空栈,可以理解为分块
B
F
S
BFS
BFS
则复杂度为
O
(
q
n
m
h
/
E
)
+
O
(
q
E
)
O(qnmh/E) + O(qE)
O(qnmh/E)+O(qE),当
E
=
n
m
h
E = \sqrt{nmh}
E=nmh,取得最小值
时间复杂度:
O
(
n
m
h
+
q
n
m
h
)
O(nmh + q\sqrt{nmh})
O(nmh+qnmh)
核心:定期重构,分块BFS
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
//#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
typedef long long ll;
using pii = pair <ll,int>;
const int maxn = 2e5 + 5;
int n, m, h, q, dis[maxn];
int to[10][5] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
struct node{
int x, y, z;
int step;
};
vector <node> s;
int getid(int x, int y, int z){
return n*m*(z-1) + n*(y-1) + x;
}
int getdis(node a, node b){
return abs(a.x-b.x) + abs(a.y-b.y) + abs(a.z-b.z);
}
void bfs(){
queue <node> Q;
for(int i=0; i<s.size(); i++){
Q.push(s[i]);
dis[getid(s[i].x, s[i].y, s[i].z)] = 0;
}
s.clear();
node q, nd;
while(Q.size()){
q = Q.front(), Q.pop();
for(int i=0; i<6; i++){
nd.x = q.x + to[i][0];
nd.y = q.y + to[i][1];
nd.z = q.z + to[i][2];
nd.step = q.step + 1;
if(nd.x<1 || nd.y<1 || nd.z<1) continue;
if(nd.x>n || nd.y>m || nd.z>h) continue;
if(dis[getid(nd.x, nd.y, nd.z)] <= nd.step) continue;
dis[getid(nd.x, nd.y, nd.z)] = nd.step;
Q.push(nd);
}
}
}
int main() {
scanf("%d%d%d%d", &n, &m, &h, &q);
int sq = 2;
memset(dis, 0x3f3f3f, sizeof(dis));
while(q--){
int o, x, y, z;
scanf("%d%d%d%d", &o, &x, &y, &z);
if(o & 1){
s.push_back(node{x,y,z,0});
if(s.size() > sq) bfs();
} else {
int ans = dis[getid(x, y, z)];
for(int i=0; i<s.size(); i++)
ans = min(ans, getdis(node{x,y,z,0}, s[i]));
printf("%d\n", ans);
}
}
}