JZOJ3256. 【TJOI2013】松鼠聚会

题目大意

给定一个二维平面和平面上的 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 + 10
typedef 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值