学校模拟赛的题,我擦bzoj挂了只能手写对拍。。还好数据过了。
如果两点间距离是曼哈顿距离的话就直接前缀和搞定了,但是在本题中,dist(a,b)=max{|Xa-Xb|,|Ya-Yb|},实际上把坐标轴旋转45度之后就转化成了曼哈顿距离了。^_^。更加形象地,我们应该这么推导将原问题的距离转化成曼哈顿距离。
本题的距离:dist(a,b)=max{Xa-Xb, Ya-Yb, Yb-Ya, Xb-Xa}。
曼哈顿距离:dist(a,b)=max{Xa-Xb+Ya-Yb,Xa-Xb-Ya+Yb,-Xa+Xb+Ya-Yb,-Xa+Xb-Ya+Yb}
实际上,将上式的Xa变为下面的Xa+Ya,Ya变为下面的Xa-Ya,上式就变成下式辣!!>_<
于是,将原来的一个点{x,y},变成新的点{x',y'},同时使得{x'+y'=x;x'-y'=y},就可以用新的点跑辣!
时间复杂度O(NlogN)。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define N 200005 using namespace std; int n; ll sum[N],ans[N]; struct node{ ll x,y; int id; }a[N]; bool cmpx(node aa,node bb){ return aa.x<bb.x; } bool cmpy(node aa,node bb){ return aa.y<bb.y; } int main(){ scanf("%d",&n); int i; for (i=1; i<=n; i++){ scanf("%lld%lld",&a[i].x,&a[i].y); a[i].x<<=1; a[i].y<<=1; a[i].id=i; a[i].y=(a[i].x-a[i].y)/2; a[i].x-=a[i].y; } sort(a+1,a+n+1,cmpx); for (i=1; i<=n; i++) sum[i]=sum[i-1]+a[i].x; for (i=1; i<=n; i++) ans[a[i].id]=a[i].x*i-sum[i]+sum[n]-sum[i]-a[i].x*(n-i); sort(a+1,a+n+1,cmpy); for (i=1; i<=n; i++) sum[i]=sum[i-1]+a[i].y; for (i=1; i<=n; i++) ans[a[i].id]+=a[i].y*i-sum[i]+sum[n]-sum[i]-a[i].y*(n-i); for (i=2; i<=n; i++) ans[1]=min(ans[1],ans[i]); printf("%lld\n",ans[1]>>1); return 0; }
2016.2.18