Distance(2019年牛客多校第八场D题+CDQ+树状数组)


题目链接

传送门

思路

这个题在\(BZOJ\)上有个二维平面的版本(\(BZOJ2716\)天使玩偶),不过是权限题因此就不附带链接了,我也只是在算法进阶指南上看到过,那个题的写法是\(CDQ\),然后比赛开始半个小时我就开始写\(CDQ\)\(T\)了之后冷静分析发现复杂度我少算了个\(log\)\(CDQ\)写这题的复杂度是\(nlog^3(n)\),然后就没思路了。

赛后看\(qls\)说用三维\(bit\)可以过后试了一下\(T\)了,然后发现\(qls\)的代码当时跑了\(937ms\)应该是卡过去的,感觉是\(vector\)常数大,但是想不出除\(vector\)的其他动态开全局数组大小的方法,最后疯狂交在\(T\)了一页后成功卡过去了,下面贴一下三维\(bit\)的代码和\(CDQ\)写法(对拍了很久貌似没问题,就当过了吧~)的代码。

这两份代码的主体思路就是拆绝对值符号,然后查询时(拿\(x_1\leq x2,y_1\leq y2,z_1\leq z_2\)举例,下标为\(2\)的是查询的点)\(|x_2-x_1|+|y_2-y_1|+|z_2-z_1|=(x_2+y_2+z_2)-(x_1+y_1+z_1)\),然后就是要查询\(x_1+y_1+z_1\)的最大值用树状数组维护即可,其他情况分别移动坐标即可。

update:发现题解里面贴的那份代码的三维\(bit\)写法贼牛逼,贴的代码就改成看了那个队的代码之后写的了。

代码

//三维bit
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long LL;
typedef pair pLL;
typedef pair pLi;
typedef pair pil;;
typedef pair pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["< 0; i -= lowbit(i)) {
            for(int j = y; j > 0; j -= lowbit(j)) {
                for(int k = z; k > 0; k -= lowbit(k)) {
                    ans = max(ans, a[gethash(i, j, k)]);
                }
            }
        }
        if(ans == 0) return inf;
        return x + y + z - ans;
    }
}bit[8];

int main() {
    scanf("%d%d%d%d", &n, &m, &h, &q);
    n += 1, m += 1, h += 1;
    for(int i = 0; i < 8; ++i) bit[i].init();
    for(int  i = 1; i <= q; ++i) {
        scanf("%d%d%d%d", &op, &x, &y, &z);
        if(op == 1) {
            bit[1].update(x, y, z);
            bit[2].update(x, y, h - z);
            bit[3].update(x, m - y, z);
            bit[4].update(n - x, y, z);
            bit[5].update(n - x, m - y, z);
            bit[6].update(n - x, y, h - z);
            bit[7].update(x, m - y, h - z);
            bit[0].update(n - x, m - y, h - z);
        } else {
            int ans = inf;
            ans = min(ans, bit[1].query(x, y, z));
            ans = min(ans, bit[2].query(x, y, h - z));
            ans = min(ans, bit[3].query(x, m - y, z));
            ans = min(ans, bit[4].query(n - x, y, z));
            ans = min(ans, bit[5].query(n - x, m - y, z));
            ans = min(ans, bit[6].query(n - x, y, h - z));
            ans = min(ans, bit[7].query(x, m - y, h - z));
            ans = min(ans, bit[0].query(n - x, m - y, h - z));
            printf("%d\n", ans);
        }
    }
    return 0;
}
//CDQ
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long LL;
typedef pair pLL;
typedef pair pLi;
typedef pair pil;;
typedef pair pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<> 1;
    cdq2(l, mid), cdq2(mid + 1, r);
    int ls = l, rs = mid + 1, cnt = l;
    for(; rs <= r; ++rs) {
        for(; ls <= mid && tmp[ls].y <= tmp[rs].y; ++ls) {
            if(tmp[ls].op == 1 && tmp[ls].flag) {
                add(tmp[ls].z, tmp[ls].val);
            }
        }
        if(!tmp[rs].flag && tmp[rs].op == 2) ans[tmp[rs].id] = min(ans[tmp[rs].id], tmp[rs].val - query(tmp[rs].z));
    }
    --ls;
    while(ls >= l) {
        if(tmp[ls].op == 1 && tmp[ls].flag) {
            del(tmp[ls].z);
        }
        --ls;
    }
    ls = l, rs = mid + 1;
    while(ls <= mid && rs <= r) {
        if(tmp[ls].y < tmp[rs].y) {
            pp[cnt++] = tmp[ls++];
        } else if(tmp[ls].y > tmp[rs].y) {
            pp[cnt++] = tmp[rs++];
        } else if(tmp[ls].z <= tmp[rs].z) {
            pp[cnt++] = tmp[ls++];
        } else {
            pp[cnt++] = tmp[rs++];
        }
    }
    while(ls <= mid) pp[cnt++] = tmp[ls++];
    while(rs <= r) pp[cnt++] = tmp[rs++];
    for(int i = l; i <= r; ++i) tmp[i] = pp[i];
}

void cdq1(int l, int r) {
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq1(l, mid), cdq1(mid + 1, r);
    int ls = l, rs = mid + 1, cnt = l;
    while(ls <= mid && rs <= r) {
        if(a[ls].x < a[rs].x) {
            tmp[cnt] = a[ls++];
            tmp[cnt++].flag = 1;
        } else if(a[ls].x > a[rs].x) {
            tmp[cnt] = a[rs++];
            tmp[cnt++].flag = 0;
        } else if(a[ls].y < a[rs].y) {
            tmp[cnt] = a[ls++];
            tmp[cnt++].flag = 1;
        } else if(a[ls].y > a[rs].y) {
            tmp[cnt] = a[rs++];
            tmp[cnt++].flag = 0;
        } else if(a[ls].z <= a[rs].z) {
            tmp[cnt] = a[ls++];
            tmp[cnt++].flag = 1;
        } else {
            tmp[cnt] = a[rs++];
            tmp[cnt++].flag = 0;
        }
    }
    while(ls <= mid) {
        tmp[cnt] = a[ls++];
        tmp[cnt++].flag = 1;
    }
    while(rs <= r) {
        tmp[cnt] = a[rs++];
        tmp[cnt++].flag = 0;
    }
    for(int i = l; i <= r; ++i) a[i] = tmp[i];
    cdq2(l, r);
}

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif
    scanf("%d%d%d%d", &n, &m, &h, &q);
    n += 1, m += 1, h += 1;
    for(int i = 1; i <= q; ++i) {
        scanf("%d%d%d%d", &op, &x, &y, &z);
        a[i] = {i, x, y, z, op, 0, 0};
    }
    //x,y,z
    for(int i = 1; i <= q; ++i) {
        ans[i] = inf;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    cdq1(1, q);

    //x,y,-z
    for(int i = 1; i <= q; ++i) {
        a[i].z = h - a[i].z;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    //x,-y,z
    for(int i = 1; i <= q; ++i) {
        a[i].z = h - a[i].z;
        a[i].y = m - a[i].y;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    //-x,y,z
    for(int i = 1; i <= q; ++i) {
        a[i].y = m - a[i].y;
        a[i].x = n - a[i].x;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    //-x,-y,z
    for(int i = 1; i <= q; ++i) {
        a[i].y = m - a[i].y;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    //-x,y,-z
    for(int i = 1; i <= q; ++i) {
        a[i].y = m - a[i].y;
        a[i].z = h - a[i].z;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    //x,-y,-z
    for(int i = 1; i <= q; ++i) {
        a[i].x = n - a[i].x;
        a[i].y = m - a[i].y;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    //-x,-y,-z
    for(int i = 1; i <= q; ++i) {
        a[i].x = n - a[i].x;
        a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
    }
    sort(a + 1, a + q + 1);
    cdq1(1, q);

    sort(a + 1, a + q + 1);
    for(int i = 1; i <= q; ++i) {
        if(a[i].op == 2) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}

相关