JZOJ3256. 【TJOI2013】松鼠聚会

来源:互联网 发布:网络会计的发展阶段 编辑:程序博客网 时间:2024/04/26 15:53

题目大意

给定一个二维平面和平面上的n个点。
求一个点,使得其他所有点到它的切比雪夫距离之和最小。
两点(x1,y1),(x2,y2)间的切比雪夫距离:d=max(|x1x2|,|y1y2|)

Data Constraint
n100000

题解

如果是曼哈顿距离,那这题就很简单了,直接分类讨论一下,然后树状数组查询。
现在考虑如何将切比雪夫距离转化成曼哈顿距离。

切比雪夫距离转化曼哈顿距离

先将原平面旋转45°,那么点(x,y)就变成了(xy,x+y),然后在新的平面内求曼哈顿距离,可以发现,这恰好是原切比雪夫距离的两倍。

然后问题就顺利解决了。

时间复杂度:O(nlogn)

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std ;#define N 100000 + 10typedef long long ll ;struct Note {    int v , h ;} tpx[N] , tpy[N] ;struct Point {    int x , y ;    Point ( int X = 0 , int Y = 0 ) { x = X , y = Y ; }} P[N] ;struct Tree {    ll sum ;    int tot ;    Tree ( ll S = 0 , int T = 0 ) { sum = S , tot = T ; }} Tr[2][N] ;Tree operator + ( Tree a , Tree b ) { return Tree( a.sum + b.sum , a.tot + b.tot ) ; }int Orix[N] , Oriy[N] ;int n , Cntx , Cnty ;ll ans = 1e15 ;bool cmp( Note a , Note b ) { return a.v < b.v ; }void PreX() {    sort( tpx + 1 , tpx + n + 1 , cmp ) ;    tpx[0].v = 0x7FFFFFFF ;    for (int i = 1 ; i <= n ; i ++ ) {        if ( tpx[i].v != tpx[i-1].v ) ++ Cntx ;        Orix[Cntx] = P[tpx[i].h].x ;        P[tpx[i].h].x = Cntx ;    }}void PreY() {    sort( tpy + 1 , tpy + n + 1 , cmp ) ;    tpy[0].v = 0x7FFFFFFF ;    for (int i = 1 ; i <= n ; i ++ ) {        if ( tpy[i].v != tpy[i-1].v ) ++ Cnty ;        Oriy[Cnty] = P[tpy[i].h].y ;        P[tpy[i].h].y = Cnty ;    }}int lowbit( int x ) { return x & (-x) ; } ;void Insert( int k , int x , Tree del ) {    while ( x <= n ) {        Tr[k][x] = Tr[k][x] + del ;        x += lowbit(x) ;    }}Tree Find( int k , int x ) {    Tree ret = Tree(0,0) ;    while ( x >= 1 ) {        ret = ret + Tr[k][x] ;        x -= lowbit(x) ;    }    return ret ;}int main() {    scanf( "%d" , &n ) ;    for (int i = 1 ; i <= n ; i ++ ) {        scanf( "%d%d" , &P[i].x , &P[i].y ) ;        P[i] = Point( P[i].x - P[i].y , P[i].x + P[i].y ) ;        tpx[i].v = P[i].x ;        tpy[i].v = P[i].y ;        tpx[i].h = tpy[i].h = i ;    }    PreX() ;    PreY() ;    for (int i = 1 ; i <= n ; i ++ ) {        Insert( 0 , P[i].x , Tree( Orix[P[i].x] , 1 ) ) ;        Insert( 1 , P[i].y , Tree( Oriy[P[i].y] , 1 ) ) ;    }    for (int i = 1 ; i <= n ; i ++ ) {        ll now = 0 ;        Tree All = Find( 0 , Cntx ) ;        Tree Lef = Find( 0 , P[i].x - 1 ) ;        Tree Rig = Tree( All.sum - Lef.sum , All.tot - Lef.tot ) ;        now = (ll)Lef.tot * Orix[P[i].x] - Lef.sum ;        now += Rig.sum - (ll)Rig.tot * Orix[P[i].x] ;        All = Find( 1 , Cnty ) ;        Lef = Find( 1 , P[i].y - 1 ) ;        Rig = Tree( All.sum - Lef.sum , All.tot - Lef.tot ) ;        now += (ll)Lef.tot * Oriy[P[i].y] - Lef.sum ;        now += (ll)Rig.sum - (ll)Rig.tot * Oriy[P[i].y] ;        ans = min( ans , now ) ;    }    printf( "%lld\n" , ans / 2 ) ;    return 0 ;}

以上.

1 0