2019牛客暑期多校训练营(第八场)D Distance —— 三维树状数组求空间中与某个点最近的点的曼哈顿距离

This way

题意:

两种操作:
1 x,y,h表示在x,y,h位置添加一个点
2 x,y,h表示询问与这个位置最近的点的曼哈顿距离是多少

题解:

cf上有一道很像的题目,那个是问三维空间中最远的两个点的距离,用8个线段树维护,这道题线段树我空间开不下,所以用树状数组。3个符号,总共有8种情况。但是值会有负数,所以x需要+n+1,y+m+1,z+h+1。
哈希值表示空间中每个点在一维上独立存在的值,因为y+m+1可能会=2m+1,所以需要乘上2m+2
那么我们为什么查询的是每一个点的x,y,z比他小的情况呢?
因为对于8种情况中的这种情况,我们是考虑了查询的点的三维的值-被查询的点的三维的值是非负数的情况,比如x1=1和x2=3的时候,我们一定查的是-x1与-x2的情况,因为这样才是减去之后的绝对值

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int n,m,h;
int get_hash(int x,int y,int z){return x*(2*m+2)*(2*h+2)+y*(2*h+2)+z;}
struct node
{
    int mx[N];
    int lowbit(int x){return x&(-x);}
    void update(int x,int y,int z,int v)
    {
        for(int i=x;i<=n*2+5;i+=lowbit(i))
            for(int j=y;j<=m*2+5;j+=lowbit(j))
                for(int k=z;k<=h*2+5;k+=lowbit(k))
                    mx[get_hash(i,j,k)]=max(mx[get_hash(i,j,k)],v);
    }

    int query(int x,int y,int z)
    {
        int ans=-1e9;
        for(int i=x;i;i-=lowbit(i))
            for(int j=y;j;j-=lowbit(j))
                for(int k=z;k;k-=lowbit(k))
                    ans=max(ans,mx[get_hash(i,j,k)]);
        return ans;
    }
}tr[8];
int xmov[]={1,1,1,1,-1,-1,-1,-1};
int ymov[]={1,1,-1,-1,1,1,-1,-1};
int zmov[]={1,-1,1,-1,1,-1,1,-1};
int main()
{
    for(int i=0;i<8;i++)
        for(int j=0;j<N;j++)
            tr[i].mx[j]=-1e9;
    int q;
    scanf("%d%d%d%d",&n,&m,&h,&q);
    while(q--)
    {
        int x,y,z,op;
        scanf("%d%d%d%d",&op,&x,&y,&z);
        if(op-2)
            for(int i=0;i<8;i++)
                tr[i].update(n+x*xmov[i]+1,m+y*ymov[i]+1,h+z*zmov[i]+1,x*xmov[i]+y*ymov[i]+z*zmov[i]);
        else
        {
            int ans=1e9;
            for(int i=0;i<8;i++)
            {
                ans=min(ans,x*xmov[i]+y*ymov[i]+z*zmov[i]-tr[i].query(n+x*xmov[i]+1,m+y*ymov[i]+1,h+z*zmov[i]+1));
                //printf("%d\n",tr[i].query(n+x*xmov[i]+1,m+y*ymov[i]+1,h+z*zmov[i]+1));
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值