2019牛客第八場多校 D_Distance 三維BIT或定期重建套路

@(2019牛客暑期多校訓練營(第八場)D_Distance)

題意:

在三維空間\((n\times m\times h\le 100000)\)內,有\(q(q\le 100000)\)次操作。操作\(1\):添加一個點進入空間;操作\(2\):查詢最近點對。


分析:

比賽時聽G黃說完題意感覺看似好像裸題,一道在二維平面上操作完全的題:BZOJ2716
那麼KD-Tree還是四維偏序問題呢?(原來都不是。。出題人放出豪言:KD-Tree想過?不可能的
解法1:三維BIT - 862ms

  • 把曼哈頓距離的絕對值去掉後,共有8種情況。
  • 用8個BIT把每個點拆掉絕對值後的8種貢獻記錄一下即可。
  • 比如這種情況:這個點在其他點的左後下方時:\(len=|x1-x2|+|y1-y2|+|z1-z2|=(x1+y1+z1)-(x2+y2+z2)\)。就\(update(x2,y2,z2)\),值爲\(-(x2+y2+z2)\)。以此類推。
  • 我們知道對於兩個確定的點,他們相對位置也確定了,顯然\(p2\)在用\(p1\)的正確相對位置的\(query()\)求出來的距離一定是最小的。這種做法正確性十分顯然。然後BIT常數非常小,很容易過去的。

解法2:定期重構+BFS - 86ms (ps:好像是最快的
定期重構這應該是一個很常見的套路的吧?有些分塊好像經常有這種操作?
在這裏插入圖片描述

  • 對三維空間維護一個值\(dis[i]\),表示離當前點\(i\)位置的最近點距離。
  • 當新加入的點的數量小於閾值MX時,暴力比對這些新加入的點。
  • 當達到了閾值MX時,就用這些新加入的點鬆弛我們的\(dis[]\)即可。
  • 代碼挺好懂的。。。
    Code1
const int MXN = 3e3 + 7;  
const int MXE = 2e6 + 7;  
typedef vector<int> VI;  
typedef vector<VI > VVI;  
typedef vector<VVI > VVVI;  
//mat c(a.size(), vec(b[0].size(), 0));
//VVVI bit(n+1,VVI(m+1, VI(h+1, INF)));
int n, m, h, q;  
struct BIT {  
    int n, m, h;  
    vector<vector<vector<int> > > bit;  
    void init(int _n, int _m, int _h) {  
        n = _n, m = _m, h = _h;  
        bit = VVVI(n+1,VVI(m+1, VI(h+1, INF)));  
    }  
    void update(int _x, int _y, int _z, int v) {  
        for(int x = _x; x <= n; x += lowbit(x)) {  
            for(int y = _y; y <= m; y += lowbit(y)) {  
                for(int z = _z; z <= h; z += lowbit(z)) {  
                    bit[x][y][z] = sml(bit[x][y][z], v);  
                }  
            }  
        }  
    }  
    int query(int _x, int _y, int _z) {  
        int res = INF;  
        for(int x = _x; x > 0; x -= lowbit(x)) {  
            for(int y = _y; y > 0; y -= lowbit(y)) {  
                for(int z = _z; z > 0; z -= lowbit(z)) {  
                    res = sml(bit[x][y][z], res);  
                }  
            }  
        }  
        return res;  
    }  
}bit[8];  
int main() {  
#ifndef ONLINE_JUDGE  
  freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);  
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);  
#endif  
  n = read(), m = read(), h = read(), q = read();  
    int opt, x, y, z, ans;  
    for(int i = 0; i < 8; ++i) bit[i].init(n, m, h);  
    while(q --) {  
        opt = read(), x = read(), y = read(), z = read();  
        if(opt == 1) {  
            for(int i = 0; i < 8; ++i) {  
                int v = (i&1?x:-x) + ((i>>1)&1?y:-y) + ((i>>2)&1?z:-z);  
//                debug(i, i&1?x:n+1-x, (i>>1)&1?y:m+1-y, (i>>2)&1?z:h+1-z, v)  
//                debug(i&1?n+1-x:x, (i>>1)&1?m+1-y:y, (i>>2)&1?h+1-z:z)  
  bit[i].update(i&1?n+1-x:x, (i>>1)&1?m+1-y:y, (i>>2)&1?h+1-z:z, v);  
            }  
        }else {  
            ans = INF;  
            for(int i = 0; i < 8; ++i) {  
                int v = (i&1?-x:x) + ((i>>1)&1?-y:y) + ((i>>2)&1?-z:z);  
//                debug(x, y, z)  
//                debug(opt, i&1?n+1-x:x, (i>>1)&1?m+1-y:y, (i>>2)&1?h+1-z:z)  
  ans = sml(ans, v + bit[i].query(i&1?n+1-x:x, (i>>1)&1?m+1-y:y, (i>>2)&1?h+1-z:z));  
            }  
            printf("%d\n", ans);  
        }  
    }  
    return 0;  
}

Code2

const int MXN = 1e6 + 7;  
const int MXE = 2e6 + 7;  
typedef vector<int> VI;  
typedef vector<VI > VVI;  
typedef vector<VVI > VVVI;  
//mat c(a.size(), vec(b[0].size(), 0));  
int n, m, h, q;  
const int MX = 1000;  
VI X, Y, Z;  
int dis[MXN];  
namespace lh {  
    int hash(int x, int y, int z) {  
        return x * m * h + y * h + z;  
    }  
}  
struct lp {  
    int x, y, z;  
};  
int dir[6][3] = {1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1};  
void rebuild() {  
    queue<lp> Q;  
    for(int i = 0; i < SZ(X); ++i) {  
        dis[lh::hash(X[i], Y[i], Z[i])] = 0;  
        Q.push({X[i], Y[i], Z[i]});  
    }  
    while(!Q.empty()) {  
        lp A = Q.front(); Q.pop();  
        for(int i = 0; i < 6; ++i) {  
            int px = A.x + dir[i][0], py = A.y + dir[i][1], pz = A.z + dir[i][2];  
            if(px < 0 || py < 0 || pz < 0 || px >= n || py >= m || pz >= h || dis[lh::hash(px, py, pz)] <= dis[lh::hash(A.x, A.y, A.z)] + 1) continue;  
            dis[lh::hash(px, py, pz)] = dis[lh::hash(A.x, A.y, A.z)] + 1;  
            Q.push(lp{px, py, pz});  
        }  
    }  
    X.clear(), Y.clear(), Z.clear();  
}  
int main() {  
#ifndef ONLINE_JUDGE  
  freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);  
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);  
#endif  
  n = read(), m = read(), h = read(), q = read();  
    int opt, x, y, z, ans;  
    clr(dis, 0x3f);  
    while(q --) {  
        opt = read(), x = read(), y = read(), z = read();  
        -- x, -- y, -- z;  
        if(opt == 1) {  
            X.eb(x), Y.eb(y), Z.eb(z);  
        }else {  
            ans = dis[lh::hash(x, y, z)];  
            for(int i = 0; i < SZ(X); ++i) ans = sml(ans, abs(x - X[i]) + abs(y - Y[i]) + abs(z - Z[i]));  
            printf("%d\n", ans);  
        }  
        if(1 || SZ(X) == MX) rebuild();  
    }  
    return 0;  
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章