省选专练之棋盘问题

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/83154234

小 O 对国际象棋有着浓厚的兴趣,因为他水平高超,每次人机对战他总是轻松获胜,所 以他决定自己跟自己下国际象棋。

小 O 的棋盘非常大,达到了 1 0 9 1 0 9 10^{9}∗10^{9} ,现在他在棋盘上摆放了 n 个国王,并对你提出 了 q 次询问,每次询问指定一个坐标,问将所有国王从初始位置全部移动到这个坐标所需要 的最小步数是多少,询问之间相互独立,也就是说每次询问结束后国王会全部回到原来位置。

注意:由于小 O 担心大家无法理解过于高深的规则,所以在本题中,国王之间不会发生 相互攻击而且多个国王可以同时处在一个格子中, 国际象棋中国王一步只能移动到与其八 连通的格子中。

由于国王是可以斜着走
所以较小的明显没有用,直接斜着走就好了。
实际答案就是切比雪夫距离。

这实际上就是模板了
我们转成曼哈顿距离,然后维护前缀和就好了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int INT;
#define int long long
const int N=1e6+1000;
inline void read(int &x){
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
struct Point{
	int x,y;
}Q[N];
int Sx[N];
int Sy[N];
int Px[N];
int Py[N];
int q;
int n;
signed main(){
//	freopen("test.in","r",stdin);
	int Cas;
	read(Cas);
	while(Cas--){
		read(n);read(q);
		for(int i=1;i<=n;++i){
			int x,y;
			read(x);
			read(y);
			Px[i]=x+y;
			Py[i]=x-y;
		}	
		for(int i=1;i<=q;++i){
			int x,y;
			read(x);
			read(y);
			Q[i].x=(x+y);
			Q[i].y=(x-y);
		}
		sort(Px+1,Px+1+n);
		sort(Py+1,Py+1+n);
		for(int i=1;i<=n;++i){
			Sx[i]=Sx[i-1]+Px[i];
			Sy[i]=Sy[i-1]+Py[i];
		}
		for(int i=1;i<=q;++i){
			int ans=0,pos;
			pos=upper_bound(Px+1,Px+1+n,Q[i].x)-Px;
			if(Px[1]<=Q[i].x){
				ans+=(pos-1)*Q[i].x-Sx[pos-1];
			}
			if(Q[i].x<Px[n]){
				ans+=Sx[n]-Sx[pos-1]-(n-pos+1)*Q[i].x;
			}
			pos=upper_bound(Py+1,Py+1+n,Q[i].y)-Py;
			if(Py[1]<=Q[i].y){
				ans+=(pos-1)*Q[i].y-Sy[pos-1];
			}	
			if(Q[i].y<Py[n]){
				ans+=Sy[n]-Sy[pos-1]-(n-pos+1)*Q[i].y;
			}	
			cout<<ans/2<<'\n';	
		}
	}
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/83154234