最近/最远曼哈顿距离

本文都是以二维举例的,实际上变成更多维也是差不多的情况啦,只是每个点的状态多了一些而已。

最远曼哈顿距离:

假设有两个点A(xi,yi),B(xj,yj)

则两点之间的曼哈顿距离为 |xi-xj|+|yi-yj|,根据两个点之间的位置关系,可以分为四种情况:(把相同点的坐标放在一起了)

即 (xi+yi)+(-xj-yj), (-xi+yi)+(xj-yj), (xi-yi)+(-xj+yj),(-xi-yi)+(xj+yj)

显然|xi-xj|=max(xi-xj,xj-xi),|yi-yj|=max(yi-yj,yj-yi);

|xi-xj|+|yi-yj|=max(xi-xj,xj-xi)+max(yi-yj,yj-yi)=max((xi-xj)+(yi-yj),(xi-xj)+(yj-yi),(xj-xi)+(yi-yj),(xj-xi)+(yj-yi))

=max( (xi+yi)+(-xj-yj), (-xi+yi)+(xj-yj), (xi-yi)+(-xj+yj),(-xi-yi)+(xj+yj) )

所以两个点之间的曼哈顿距离=max( (xi+yi)+(-xj-yj), (-xi+yi)+(xj-yj), (xi-yi)+(-xj+yj),(-xi-yi)+(xj+yj) ),4种情况取最大的一个就是了。

假设我们现在要求点A(xi,yi)到很多其他点的最远曼哈顿距离,就是max( (xi+yi)+max{-xj-yj},(-xi+yi)+max{xj-yj}, (xi-yi)+max{-xj+yj},(-xi-yi)+max{xj+yj} ); 对于每种xi,yi的符号组合(一共四种)找到对应的其他点的符号组合中的最大值。

如果要求两个点A(xi,yi),B(xj,yj)到其他点的最远曼哈顿距离,就是max(xi+yi,xj+yj)) +max{-x'-y'},max(xi-yi,xj-yj)+max{-x'+y'}, max(-xi-yi,-xj-yj)+max{x'+y'} , max(-xi+yi,-xj+yj)+max{x'-y'}.

所以如果求多个点相互之间的最远曼哈顿距离就是 max( max{x+y}+max{-x'-y'}, max{x-y}+max{-x'+y'}, max{-x+y}+max{x'-y'},max{-x-y}+max{x'+y'}).此时维护每个点四种符号组合情况下的最大值就好啦。

脑子拐不过弯怎么都没法感性理解|xi-xj|+|yi-yj|=max((xi-xj)+(yi-yj),(xi-xj)+(yj-yi),(xj-xi)+(yi-yj),(xj-xi)+(yj-yi))……啰啰嗦嗦了一堆总算稍微有了点印象嘤嘤嘤。

例题:hdu 4666

最近曼哈顿距离:

根据两个点之间的位置关系,可以拆掉它们之间曼哈顿距离表示的绝对值:

最近/最远曼哈顿距离_第1张图片

1.dis=x1-x2+y1-y2  (x1>x2,y1>y2)

2.dis=x1-x2+y2-y1  (x1>x2,y1

3.dis=x2-x1+y2-y1(x1

4.dis=x2-x1+y1-y2(x1y2)

把相同点的坐标放在一起,右边的范围全部变成<,就变成了这样:

1. dis=(x1+y1)-(x2+y2) (x2

2. dis=(x1-y1)-(x2-y2) (x2

3. dis=(-x1-y1)-(-x2-y2)  (-x2<-x1,-y2<-y1)

4.dis=(-x1+y1)-(-x2+y2) (-x2<-x1,y2

开四个树状数组,分别将每个点的四种状态都在对应树状数组的对应位置记录下来。

假设我们要求A(x,y)与其他点之间的最近曼哈顿距离,则只需遍历A的四个状态(00,01,10,11,0表示负,1表示正),在对应的树状数组(00对应00,01->01,10->10,11->11)里找到满足位置要求的最大值。(因为以上几条式子中间都是减号,被减的数越大dis就越小)。

比如每个点的横坐标范围为c,纵坐标范围为r时,点A(x,y)的位置就可以是 x*c+y,那么所有位置在[1,x*c+y]范围内的点B(x',y')都是满足x'

好像很难讲清楚,就这样吧啊哈哈。

例题:

https://ac.nowcoder.com/acm/contest/888/D

真是被这题秀到了,还是见识太少呀。贴一贴这题的代码:

#include
using namespace std;
const int maxn=1e5+15;
int n,m,h,q;
struct BIT{
    int d[maxn];
    void init(){memset(d,128,sizeof(int)*(n*m*h+5));}
    inline int getid(int i,int j,int k){return (i-1)*m*h+(j-1)*h+k;}
    inline void getmax(int &a,int b){ a=(b>a)?b:a;}
    inline void update(int x,int y,int z,int val){
       // printf(" x=%d y=%d z=%d val=%d\n",x,y,z,val);
        for(int i=x;i<=n;i+=i&-i)
            for(int j=y;j<=m;j+=j&-j)
                for(int k=z;k<=h;k+=k&-k)
                    getmax(d[getid(i,j,k)],val);//getid(i,j,k)这个位置被更新了一个值
    }
    inline int sum(int x,int y,int z){
        int res=-2e9;
        for(int i=x;i>0;i-=i&-i)//询问所有x'<=x,y'<=y,z'<=z范围内的最大值,此处x,x'等都是包括符号了的哦
            for(int j=y;j>0;j-=j&-j)
                for(int k=z;k>0;k-=k&-k)
                    getmax(res,d[getid(i,j,k)]);
        return res;
    }
}t[8];
int main(){
    scanf("%d%d%d%d",&n,&m,&h,&q);
    for(int i=0;i<8;i++) t[i].init();
    int op,x,y,z,xx,yy,zz,xxx,yyy,zzz,ans;
    while(q--){
        ans=2e9;
        scanf("%d%d%d%d",&op,&x,&y,&z);
        for(int i=0;i<8;i++){
            if(4&i) xx=xxx=x;//+1是因为树状数组下标不可以为负
            else xx=n-x+1,xxx=-x;
            if(2&i) yy=yyy=y;
            else yy=m-y+1,yyy=-y;
            if(1&i) zz=zzz=z;
            else zz=h-z+1,zzz=-z;
            if(op==1){
                t[i].update(xx,yy,zz,xxx+yyy+zzz);
            }else{
                ans=min(ans,xxx+yyy+zzz-t[i].sum(xx,yy,zz));
            }
        }
        if(op==2) printf("%d\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(树状数组,曼哈顿距离)