2019牛客多校第八场D Distance(重构思维)题解

题意:

传送门
三维长方体有\(n*m*h <=1e5\),现给定\(q<=1e5\)个询问,每次询问给出:
\(1\ x\ y\ z\)表示把\(x\ y\ z\)标记一下
\(2\ x\ y\ z\)询问\(x\ y\ z\)和已经标记的点的最近曼哈顿距离是多少

思路:

我们可以花\(O(nmh)\)的时间预处理出所有点到已标记点的最小距离,也可以花\(O(L)\)的时间处理出某点到\(L\)个点的最小距离,那么中和一下,我们用一个栈表示还未预处理的点,一旦栈超过\(L\)那就拿去预处理,答案为预处理出的最小值和遍历栈中最小值的最小值。时间复杂度\(O(nmhq/L+qL)\),当\(L = \sqrt{nmh}\)时取到最小值。

代码:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 131;
const ll MOD = 1e9;
using namespace std;
int n, m, h, q, e;
int dis[maxn * 2];
int getid(int x, int y, int z){
    return n * m * (z - 1) + m * (x - 1) + y;
}
struct Node{
    int x, y, z;
    int step;
};
vector<Node> s;
int to[6][3] = {{0, 0, 1}, {0, 0, -1}, {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};
void bfs(){
    queue<Node> q;
    while(!q.empty()) q.pop();
    Node a, b;
    for(int i = 0; i < s.size(); i++){
        a.x = s[i].x, a.y = s[i].y, a.z = s[i].z, a.step = 0;
        dis[getid(a.x, a.y, a.z)] = 0;
        q.push(a);
    }
    s.clear();
    while(!q.empty()){
        a = q.front();
        q.pop();
        for(int i = 0; i < 6; i++){
            b.x = a.x + to[i][0];
            b.y = a.y + to[i][1];
            b.z = a.z + to[i][2];
            b.step = a.step + 1;
            if(b.x < 1 || b.y < 1 || b.z < 1 || b.x > n || b.y > m || b.z > h) continue;
            if(dis[getid(b.x, b.y, b.z)] <= b.step) continue;    //!!!
            dis[getid(b.x, b.y, b.z)] = b.step;
            q.push(b);
        }
    }
}
int getdis(int x, int y, int z, const Node c){
    return abs(x - c.x) + abs(y - c.y) + abs(z - c.z);
}
int main(){
    scanf("%d%d%d%d", &n, &m, &h, &q);
    e = sqrt(n * m * h);
    s.clear();
    memset(dis, INF, 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() >= e) bfs();
        }
        else{
            int ans = dis[getid(x, y, z)];
            for(int i = 0; i < s.size(); i++){
                ans = min(ans, getdis(x, y, z, s[i]));
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}

posted @ 2019-08-22 14:55  KirinSB  阅读(209)  评论(0)    收藏  举报