题目链接:https://ac.nowcoder.com/acm/contest/888/D
waht?什么定期重构?
献上题解:
总结:取一个le值为sqrt(n*m*h)当现在的点小于le值,那么进行暴力匹配最近的点,如果大于,那么用这些点跑一次多源最短路的bfs,再清除这些点。。太秀了,学到了学到了~
代码:
/*
定期重构,当前点小于某个,直接暴力枚举,大于某个值,跑一边bfs
第一次见这样的做法。。太秀了吧~~
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e5+10;
int dis[N];
int n,m,h,q;
struct node
{
int x,y,z;
};
vector<node>G;
int getdis(node a,node b)
{
return abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z);
}
int getid(int x,int y,int z)
{
return (x-1)*m*h+(y-1)*h+z-1;
}
int dir[6][3]={1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1};
void bfs()
{
queue<node>que;
for(node v:G) {
dis[getid(v.x,v.y,v.z)]=0;
que.push({v.x,v.y,v.z});
}
while(que.size())
{
node now=que.front();que.pop();
for(int i=0;i<6;++i)
{
int x=now.x+dir[i][0];
int y=now.y+dir[i][1];
int z=now.z+dir[i][2];
if(x<=0||x>n||y<=0||y>m||z<=0||z>h) continue;
if(dis[getid(x,y,z)]>dis[getid(now.x,now.y,now.z)]+1)
{
dis[getid(x,y,z)]=dis[getid(now.x,now.y,now.z)]+1;
que.push({x,y,z});
}
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&h,&q);
int x,y,z,ty;
memset(dis,inf,sizeof(dis));
int le=sqrt(n*m*h);
while(q--)
{
scanf("%d%d%d%d",&ty,&x,&y,&z);
if(ty==1)
{
G.push_back({x,y,z});
if(G.size()==le)
{
bfs();
G.clear();
}
}
else{
int ans=dis[getid(x,y,z)];
for(node v:G) ans=min(ans,getdis({x,y,z},v));
printf("%d\n",ans);
}
}
}