D-Distance_2019牛客暑期多校训练营(第八场)

题目链接

Distance

题意

1<=nmh,q<=1e5
q个操作

  • 1 x y z往坐标里加入一个点
  • 2 x y z查询距离该点最近的点的距离(曼哈顿距离)

题解

做法一

将要插入的点保存在一个队列中,当队列中的点数达到一个阈值就把队列中所有点取出,暴力的bfs一次把答案记录在\(dis[getid(x,y,z)]\)中表示距离点\((x,y,z)\)最近的点的距离,查询的时候就取暴力的计算查询点和队列中每个点的距离,再和已经插入的点也就是dis数组取最小值,当阈值取\(\sqrt{nmh}\)时复杂度为\(O(\frac{qnmh}E + qE) = O(nmh + q\sqrt{nmh})\)

做法二

将距离公式\(|x_0-x_i| + |y_0-y_i| + |z_0-z_i|\)的绝对值拆开有八种情况\(\pm(x_0-x_i) \pm (y_0-y_i) \pm (z_0-z_i)\)
这八种情况的最大值就是真正的距离,我们将插入的点分成\((\pm x, \pm y, \pm z)\)八种情况分别插入八个树状数组,树状数组维护\(x_i <= x, y_i <= y, z_i <= z的x+y+z\)的最大值,目的是为了把求最近点的距离转换成求\((x+y+z-x_i-y_i-z_i)\)的最小值,查询的时候对八个树状数组答案取min就行了

代码

做法一

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
  
const int mx = 1e5+5;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
const int dir[6][3] = {{0,0,1}, {0,0,-1}, {0,1,0}, {0,-1,0}, {1,0,0}, {-1,0,0}};
int dis[mx];
int n, m, h, q;
struct node {
    int x, y, z, step;
};
 
vector <node> v;
queue <node> Q;
 
int getid(int x, int y, int z) {
    return (x-1)*m*h + (y-1)*h + z;
}
 
int getdis(int x, int y, int z, int a, int b, int c) {
    return abs(x-a) + abs(y-b) + abs(z-c);
}
 
int main() {
    for (int i = 0; i < mx; i++) dis[i] = INF;
     
    scanf("%d%d%d%d", &n, &m, &h, &q);
    int sq = sqrt(n*m*h)    ;
    while (q--) {
        int op, x, y, z;
        scanf("%d%d%d%d", &op, &x, &y, &z);
        if (op == 1) {
            v.push_back({x, y, z, 0});
            if (v.size() == sq) {
                for (int i = 0; i < v.size(); i++) {
                    Q.push(v[i]);
                    dis[getid(v[i].x, v[i].y, v[i].z)] = 0;
                }
                v.clear();
                while (!Q.empty()) {
                    node now = Q.front();
                    node next;
                    Q.pop();
                    for (int i = 0; i < 6; i++) {
                        next.x = now.x + dir[i][0];
                        next.y = now.y + dir[i][1];
                        next.z = now.z + dir[i][2];
                        if (next.x < 1 || next.x > n || next.y < 1 || next.y > m || next.z < 1 || next.z > h) continue;
                        next.step = now.step + 1;
                        if (next.step < dis[getid(next.x, next.y, next.z)]) {
                            dis[getid(next.x, next.y, next.z)] = next.step;
                            Q.push(next);
                        }
                    }
                }
            }
        } else {
            int ans = dis[getid(x, y, z)];
            for (int i = 0; i < v.size(); i++) {
                ans = min(ans, getdis(x, y, z, v[i].x, v[i].y, v[i].z));
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}

做法二

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int mx = 8e5+5;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
const int dir[8][3] = {{1,1,1}, {1,1,-1}, {1,-1,1}, {1,-1,-1}, {-1,1,1}, {-1,1,-1}, {-1,-1,1}, {-1,-1,-1}};
int dis[mx];
int n, m, h, q;

int getid(int x, int y, int z) {
    return (x-1)*m*h + (y-1)*h + z;
}

struct Bit {
    int a[mx];
    int lowbit(int x) {
        return x & -x;
    }
    void update(int x, int y, int z) {
        if (x < 0) x += n;
        if (y < 0) y += m;
        if (z < 0) z += h;
        for (int i = x; i <= n; i+=lowbit(i))
            for (int j = y; j <= m; j+=lowbit(j))
                for (int k = z; k <= h; k+=lowbit(k))
                    a[getid(i,j,k)] = max(a[getid(i,j,k)], x+y+z);
    }

    int query(int x, int y, int z) {
        if (x < 0) x += n;
        if (y < 0) y += m;
        if (z < 0) z += h;
        int ans = 0;
        for (int i = x; i > 0; i-=lowbit(i))
            for (int j = y; j > 0; j-=lowbit(j))
                for (int k = z; k > 0; k-=lowbit(k))
                    ans = max(a[getid(i,j,k)], ans);
        if (ans == 0) return INF;
        else return x+y+z-ans;
    }
}bit[8];

int main() {   
    scanf("%d%d%d%d", &n, &m, &h, &q);
    n++; m++; h++;
    while (q--) {
        int op, x, y, z;
        scanf("%d%d%d%d", &op, &x, &y, &z);
        if (op == 1) {
            for (int i = 0; i < 8; i++) {
                bit[i].update(x*dir[i][0], y*dir[i][1], z*dir[i][2]);
            }
        } else {
            int ans = INF;
            for (int i = 0; i < 8; i++) ans = min(ans, bit[i].query(x*dir[i][0], y*dir[i][1], z*dir[i][2]));
            printf("%d\n", ans);
        }
    }
    return 0;
}

posted @ 2019-08-22 17:11  奔跑的蜗new  阅读(187)  评论(0编辑  收藏  举报