题目链接:https://ac.nowcoder.com/acm/contest/888/D

waht?什么定期重构?

献上题解:

2019牛客暑期多校训练营(第八场) D-Distance (定期重构)_暴力枚举

总结:取一个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);
        }
    }
}