【bzoj3170】[Tjoi 2013]松鼠聚会 旋转坐标系
题目描述
有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1。现在N个松鼠要走到一个松鼠家去,求走过的最短距离。
输入
第一行给出数字N,表示有多少只小松鼠。0<=N<=10^5
下面N行,每行给出x,y表示其家的坐标。
-10^9<=x,y<=10^9
输出
表示为了聚会走的路程和最小为多少。
样例输入
6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2
样例输出
20
题解
旋转坐标系
题目给出的切比雪夫距离不好求,我们可以旋转坐标系,将点$(x,y)$变为$(x+y,x-y)$,转化为曼哈顿距离。
然后就可以对横纵坐标分开考虑,对于某一坐标我们要求的就是所有数与它差的绝对值之和。可以对所有数排序,然后二分查找,使用前缀和计算答案。
最后别忘了把答案除2,因为旋转坐标系的过程中相当于把距离乘了2。
#include <cstdio> #include <cstring> #include <algorithm> #define N 100010 using namespace std; typedef long long ll; ll x[N] , y[N] , tx[N] , ty[N] , sx[N] , sy[N]; int main() { int n , i , px , py; ll ans = 1ll << 62 , vx , vy; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) scanf("%lld%lld" , &vx , &vy) , x[i] = tx[i] = vx + vy , y[i] = ty[i] = vx - vy; sort(tx + 1 , tx + n + 1) , sort(ty + 1 , ty + n + 1); for(i = 1 ; i <= n ; i ++ ) sx[i] = sx[i - 1] + tx[i] , sy[i] = sy[i - 1] + ty[i]; for(i = 1 ; i <= n ; i ++ ) { px = lower_bound(tx + 1 , tx + n + 1 , x[i]) - tx , vx = (x[i] * px - sx[px]) + (sx[n] - sx[px] - x[i] * (n - px)); py = lower_bound(ty + 1 , ty + n + 1 , y[i]) - ty , vy = (y[i] * py - sy[py]) + (sy[n] - sy[py] - y[i] * (n - py)); ans = min(ans , vx + vy); } printf("%lld\n" , ans >> 1); return 0; }