bzoj3170

3170: [Tjoi 2013]松鼠聚会

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1205   Solved: 600
[ Submit][ Status][ Discuss]

Description

有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1。现在N个松鼠要走到一个松鼠家去,求走过的最短距离。

Input

第一行给出数字N,表示有多少只小松鼠。0<=N<=10^5
下面N行,每行给出x,y表示其家的坐标。
-10^9<=x,y<=10^9

Output

表示为了聚会走的路程和最小为多少。

Sample Input

6
-4 -1
-1 -2
2 -4
0 2
0 3
5 -2

Sample Output

20




做了奇怪的事情。。。
本来一个神奇的坐标转化就可以的,我用线段树强行维护了答案。
枚举每一个点为聚会的地方,周围就有八种情况(“米”字形地分开),每种情况中的点到聚会点的长度都是只用x或y,排好序丢到线段树里就可以了。
然后跑的常数是8,再加上线段树的常数,7s跑完,排行榜都不要我了。QAQ






#include <stdio.h>
#include <algorithm>

using namespace std;

//long long
const long long maxn = 140000;
const long long del = 110000;
struct node {
	long long l , r , s , siz;
	node *ll , *rr;
} pool[maxn*4] , *t;
struct dis {
	long long x , i;
} d[maxn];
struct so {
	long long x , y , b1 , b2 , i;
} s[maxn];
long long top;
long long n;
long long x[maxn] , y[maxn];
long long ans[maxn] , minn;
bool cmp ( dis x1 , dis x2 ) {
	return x1.x < x2.x;
}
bool cmp1 ( so x1 , so x2 ) {
	if ( x1.y == x2.y ) return x1.b1 < x2.b1;
	return x1.y > x2.y;
}
bool cmp2 ( so x1 , so x2 ) {
	if ( x1.x == x2.x ) return x1.b1 > x2.b1;
	return x1.x > x2.x;
}
bool cmp3 ( so x1 , so x2 ) {
	if ( x1.x == x2.x ) return x1.b2 < x2.b2;
	return x1.x < x2.x;
}
bool cmp4 ( so x1 , so x2 ) {
	if ( x1.y == x2.y ) return x1.b2 < x2.b2;
	return x1.y > x2.y;
}
bool cmp5 ( so x1 , so x2 ) {
	if ( x1.y == x2.y ) return x1.b1 < x2.b1;
	return x1.y < x2.y;
}
bool cmp6 ( so x1 , so x2 ) {
	if ( x1.x == x2.x ) return x1.b1 < x2.b1;
	return x1.x < x2.x;
}
bool cmp7 ( so x1 , so x2 ) {
	if ( x1.x == x2.x ) return x1.b2 > x2.b2;
	return x1.x > x2.x;
}
bool cmp8 ( so x1 , so x2 ) {
	if ( x1.y == x2.y ) return x1.b2 < x2.b2;
	return x1.y < x2.y;
}
void buildtree ( node *id , long long l , long long r ) {
	id -> l = l; id -> r = r;
	if ( l == r ) return ;
	long long mid = (l+r)/2;
	id -> ll = &pool[++top]; id -> rr = &pool[++top];
	buildtree ( id -> ll , l , mid ); buildtree ( id -> rr , mid + 1 , r );
}
void clear ( node *id ) {
	id -> s = id -> siz = 0;
	if ( id -> ll ) clear ( id -> ll );
	if ( id -> rr ) clear ( id -> rr );
}
void change ( node *id , long long x , long long y ) {
	//prlong longf ( "%lld %lld %lld %lld\n" , id -> l , id -> r , x , y );
	id -> s += y; id -> siz++;
	if ( id -> l == id -> r ) return ;
	long long mid = (id->l+id->r)/2;
	if ( x <= mid ) change ( id -> ll , x , y );
	else change ( id -> rr , x , y );
}
long long querys ( node *id , long long l , long long r ) {
	if ( l > r ) return 0;
	if ( id -> l == l && id -> r == r ) return id -> s;
	long long mid = (id->l+id->r)/2;
	if ( r <= mid ) return querys ( id -> ll , l , r );
	else {
		if ( l > mid ) return querys ( id -> rr , l , r );
		else return querys ( id -> ll , l , mid ) + querys ( id -> rr , mid + 1 , r );
	}
}
long long querysiz ( node *id , long long l , long long r ) {
	//prlong longf ( "%lld %lld %lld %lld\n" , id -> l , id -> r , l , r );
	if ( l > r ) return 0;
	if ( id -> l == l && id -> r == r ) return id -> siz;
	long long mid = (id->l+id->r)/2;
	if ( r <= mid ) return querysiz ( id -> ll , l , r );
	else {
		if ( l > mid ) return querysiz ( id -> rr , l , r );
		else return querysiz ( id -> ll , l , mid ) + querysiz ( id -> rr , mid + 1 , r );
	}
}
void work () {
	long long i , k;
	scanf ( "%lld" , &n );
	for ( i = 1 ; i <= n ; i++ ) {
		scanf ( "%lld%lld" , &s[i].x , &s[i].y );
		s[i].i = i;
		d[i].x = s[i].y - s[i].x; d[i].i = i;
	}
	sort ( d + 1 , d + 1 + n , cmp );
	for ( i = 1 , k = 0 ; i <= n ; i++ ) {
		if ( i == 1 || d[i].x != d[i-1].x ) k++;
		s[d[i].i].b1 = k;
	}
	for ( i = 1 ; i <= n ; i++ ) d[i].x = s[i].x + s[i].y, d[i].i = i;
	sort ( d + 1 , d + 1 + n , cmp );
	for ( i = 1 , k = 0 ; i <= n ; i++ ) {
		if ( i == 1 || d[i].x != d[i-1].x ) k++;
		s[d[i].i].b2 = k;
	}
	//for ( i = 1 ; i <= n ; i++ ) printf ( "%lld %lld %lld %lld\n" , s[i].x , s[i].y , s[i].b1 , s[i].b2 );
	t = &pool[++top];
	buildtree ( t , 1 , n );
	sort ( s + 1 , s + 1 + n , cmp1 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,1,s[i].b1) - querysiz(t,1,s[i].b1) * s[i].x);
		change ( t , s[i].b1 , s[i].x );
		//printf ( "###%lld %lld %lld\n" , i , s[i].b1 , s[i].b2 );
		//printf ( "%lld %lld %lld %lld %lld\n" , querys(t,s[i].b2+1,n) , querysiz(t,s[i].b2+1,n) , s[i].i , s[i].b2 , abs(querys(t,s[i].b2+1,n) - querysiz(t,s[i].b2+1,n) * s[i].x) );
	}
	sort ( s + 1 , s + 1 + n , cmp2 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,s[i].b1+1,n) - querysiz(t,s[i].b1+1,n) * s[i].y);
		//printf ( "%lld %lld %lld\n" , querys(t,1,s[i].b1) , querysiz(t,1,s[i].b1), s[i].i );
		change ( t , s[i].b1 , s[i].y );
	}
	sort ( s + 1 , s + 1 + n , cmp3 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,s[i].b2,n) - querysiz(t,s[i].b2,n) * s[i].y);
		change ( t , s[i].b2 , s[i].y );
	}
	sort ( s + 1 , s + 1 + n , cmp4 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,1,s[i].b2-1) - querysiz(t,1,s[i].b2-1) * s[i].x);
		change ( t , s[i].b2 , s[i].x );
	}
	sort ( s + 1 , s + 1 + n , cmp5 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,s[i].b1,n) - querysiz(t,s[i].b1,n) * s[i].x);
		change ( t , s[i].b1 , s[i].x );
	}
	sort ( s + 1 , s + 1 + n , cmp6 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,1,s[i].b1-1) - querysiz(t,1,s[i].b1-1) * s[i].y);
		change ( t , s[i].b1 , s[i].y );
	}
	sort ( s + 1 , s + 1 + n , cmp7 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,1,s[i].b2) - querysiz(t,1,s[i].b2) * s[i].y);
		change ( t , s[i].b2 , s[i].y );
	}
	//printf ( "%lld\n" , ans[5] );
	sort ( s + 1 , s + 1 + n , cmp8 );
	clear ( t );
	for ( i = 1 ; i <= n ; i++ ) {
		ans[s[i].i] += abs(querys(t,s[i].b2+1,n) - querysiz(t,s[i].b2+1,n) * s[i].x);
		change ( t , s[i].b2 , s[i].x );
	}
	minn = ans[1];
	for ( i = 2 ; i <= n ; i++ ) minn = min ( minn , ans[i] );
	//for ( i = 1 ; i <= n ; i++ ) printf ( "%lld\n" , ans[i] );
	printf ( "%lld\n" , minn );
}
int main () {
	//FILE *fpr = freopen ( "bzoj3170.in" , "r" , stdin );
	//FILE *fpw = freopen ( "bzoj3170.out" , "w" , stdout );
	work ();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值