• 最远 Manhattan 距离


    最远 Manhattan 距离

    处理问题

    K维空间下的n个点,求两点最远曼哈顿距离

    思路

    以二维为例介绍算法思想,即可类推到k维。对于P,Q两点,曼哈顿距离|Px-Qx|+|Py-Qy|可看作(±Px±Py)-(±Qx±Qy),不难发现Px应该与Qx的符号相同,Py与Qy符号相同,因此共四种情况。这样写的好处是,每个点可以表示成相同的形式(±Px±Py)。而曼哈顿距离一定是四种情况中值最大的那种,所以要求两点最远曼哈顿距离,可以枚举所有的取符号情况,对于每种情况,维护出上述表示下n个点的最大值与最小值,求出差值。则最远的曼哈顿距离一定是所有情况中的最大差值。

    代码描述

    ll max_Manhattan(ll p[][10],int n,int k)
    {
    	ll ans=0;
    	for (int s=0;s<(1<<k);++s)
    	{
    		ll mx=-1e18,mn=1e18;
    		for (int i=0;i<n;++i)
    		{
    			ll tmp=0;
    			for (int j=0;j<k;++j)
    				tmp+=(s&(1<<j))?p[i][j]:-p[i][j];
    			mx=max(mx,tmp),mn=min(mn,tmp);
    		}
    		ans=max(ans,mx-mn);
    	}
    	return ans;
    }
    

    应用

    一般题目可能不会太直白的要求最远曼哈顿距离,以今年多校的一道题为例,可以HDU上找到J.CSGO.

    题目大意:

    给n个主武器,m个副武器。每个武器有1个s属性和k个x属性。要求选取主副两把武器,使得最大。

    思路:

    现在再来看这道题,可以发现其形式很像求K维下最远曼哈顿距离。前面多的两项可以看作第k+1维,为了保证它们的形式是两项相加,将其中一个武器集合的s属性都置为负即可。然后就做一次k维下n个点和m个点之间取两点的最远曼哈顿距离。要注意,选取的点必须分属不同集合。因此我的处理方式是,每种取符号情况下,分别维护两个武器集合的最值,求差值。(也有更巧妙的处理方法,如处理两种武器的s值,最后再修正答案,这里不赘述,可以看一下该题相关博客题解)

    代码:

    #include<bits/stdc++.h>
    #define dd(x) cout<<#x<<" = "<<x<<" "
    #define de(x) cout<<#x<<" = "<<x<<"
    "
    #define sz(x) int(x.size())
    #define All(x) x.begin(),x.end()
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef pair<int,int> P;
    typedef priority_queue<int> BQ;
    typedef priority_queue<int,vector<int>,greater<int> > SQ;
    const int maxn=1e5+10,mod=1e9+7,INF=0x3f3f3f3f;
    int a[maxn][10],b[maxn][10];
    void cal(int p[][10],int n,int k,int sta,ll& mx,ll& mn)
    {
    	mx=-1e18,mn=1e18;
    	for (int i=0;i<n;++i)
    	{
    		ll tmp=0;
    		for (int j=0;j<k;++j)
    		{
    			if (sta&(1<<j))
    				tmp+=p[i][j];
    			else
    				tmp-=p[i][j];
    		}
    		mx=max(mx,tmp),mn=min(mn,tmp);
    	}
    }
    ll max_Manhattan(int n,int m,int k)
    {
    	ll ans=0,amax,amin,bmax,bmin;
    	for (int sta=0;sta<(1<<k);++sta)
    	{
    		cal(a,n,k,sta,amax,amin);
    		cal(b,m,k,sta,bmax,bmin);
    		ans=max(ans,max(amax-bmin,bmax-amin));
    	}
    	return ans;
    }
    int main()
    {
    	int  T;
    	cin>>T;
    	while (T--)
    	{
    		int n,m,k;
    		scanf("%d%d%d",&n,&m,&k);
    		for (int i=0;i<n;++i)
    			for (int j=0;j<=k;++j)
    				scanf("%d",&a[i][j]);
    		for (int i=0;i<m;++i)
    		{
    			for (int j=0;j<=k;++j)
    				scanf("%d",&b[i][j]);
    			b[i][0]*=-1;
    		}
    		printf("%lld
    ",max_Manhattan(n,m,k+1));
    	}
    	return 0;
    }
    

    再附上一道CF上的题G. Multidimensional Queries
    题目大意:给K维空间下的n个点,编号1-n。有两种操作,1重置某个编号的点的坐标,2询问某个编号区间内最远两点的曼哈顿距离。
    思路:直白的求最远曼哈顿距离,不过是带有修改操作和区间询问,因此需要线段树来维护每个取符号情况下的区间最值。思想没有变化,也不需要什么技巧,不赘述。
    代码:

    #include<bits/stdc++.h>
    #define dd(x) cout<<#x<<" = "<<x<<" "
    #define de(x) cout<<#x<<" = "<<x<<endl
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> P;
    typedef vector<int> V;
    typedef map<int,int> M;
    typedef queue<int> Q;
    typedef priority_queue<int> BQ;
    typedef priority_queue<int,vector<int>,greater<int> > SQ;
    const int maxn=2e5+10,INF=0x3f3f3f3f;
    int a[maxn][6],mx[maxn<<2][33],mn[maxn<<2][33];
    int n,k;
    inline void push_up(int id)
    {
    	for (int s=0;s<(1<<k);++s)
    		mx[id][s]=max(mx[id<<1][s],mx[id<<1|1][s]),
    		mn[id][s]=min(mn[id<<1][s],mn[id<<1|1][s]);
    }
    void cal(int p,int id)
    {
    	for (int s=0;s<(1<<k);++s)
    	{
    		int tmp=0;
    		for (int i=0;i<k;++i)
    			tmp+=(s&(1<<i))?a[p][i]:-a[p][i];
    		mx[id][s]=mn[id][s]=tmp;
    	}
    }
    void build(int l,int r,int id)
    {
    	if (l==r)
    	{
    		cal(l,id);
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,id<<1);
    	build(mid+1,r,id<<1|1);
    	push_up(id);
    }
    void upd(int p,int l,int r,int id)
    {
    	if (l==r)
    	{
    		cal(p,id);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (p<=mid)
    		upd(p,l,mid,id<<1);
    	else
    		upd(p,mid+1,r,id<<1|1);
    	push_up(id);
    }
    void qry(int L,int R,int& Max,int& Min,int l,int r,int id,int s)
    {
    	if (L<=l&&r<=R)
    	{
    		Max=max(Max,mx[id][s]),Min=min(Min,mn[id][s]);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (R>mid)
    		qry(L,R,Max,Min,mid+1,r,id<<1|1,s);
    	if (L<=mid)
    		qry(L,R,Max,Min,l,mid,id<<1,s);
    }
    int query(int L,int R)
    {
    	int ans=0;
    	for (int s=0;s<(1<<k);++s)
    	{
    		int Max=-INF,Min=INF;
    		qry(L,R,Max,Min,1,n,1,s);
    		ans=max(ans,Max-Min);
    	}
    	return ans;
    }
    int main()
    {
    	cin>>n>>k;
    	for (int i=1;i<=n;++i)
    		for (int j=0;j<k;++j)
    			scanf("%d",&a[i][j]);
    	build(1,n,1);
    	int q;
    	cin>>q;
    	while (q--)
    	{
    		int op;
    		scanf("%d",&op);
    		if (op==1)
    		{
    			int id;
    			scanf("%d",&id);
    			for (int i=0;i<k;++i)
    				scanf("%d",&a[id][i]);
    			upd(id,1,n,1);
    		}
    		else
    		{
    			int l,r;
    			scanf("%d%d",&l,&r);
    			printf("%d
    ",query(l,r));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    城市的划入划出效果
    文本溢出省略解决笔记css
    长串英文数字强制折行解决办法css
    Poj 2352 Star
    树状数组(Binary Indexed Trees,二分索引树)
    二叉树的层次遍历
    Uva 107 The Cat in the Hat
    Uva 10336 Rank the Languages
    Uva 536 Tree Recovery
    Uva10701 Pre, in and post
  • 原文地址:https://www.cnblogs.com/orangee/p/10182886.html
Copyright © 2020-2023  润新知