POJ 1990 MooFest 树状数组

MooFest
Time Limit: 1000MS
Memory Limit: 30000K
Total Submissions: 5014
Accepted: 2141

Description

Every year, Farmer John's N (1 <= N <= 20,000) cows attend "MooFest",a social gathering of cows from around the world. MooFest involves a variety of events including haybale stacking, fence jumping, pin the tail on the farmer, and of course, mooing. When the cows all stand in line for a particular event, they moo so loudly that the roar is practically deafening. After participating in this event year after year, some of the cows have in fact lost a bit of their hearing.

Each cow i has an associated "hearing" threshold v(i) (in the range 1..20,000). If a cow moos to cow i, she must use a volume of at least v(i) times the distance between the two cows in order to be heard by cow i. If two cows i and j wish to converse, they must speak at a volume level equal to the distance between them times max(v(i),v(j)).

Suppose each of the N cows is standing in a straight line (each cow at some unique x coordinate in the range 1..20,000), and every pair of cows is carrying on a conversation using the smallest possible volume.

Compute the sum of all the volumes produced by all N(N-1)/2 pairs of mooing cows.

Input

* Line 1: A single integer, N

* Lines 2..N+1: Two integers: the volume threshold and x coordinate for a cow. Line 2 represents the first cow; line 3 represents the second cow; and so on. No two cows will stand at the same location.

Output

* Line 1: A single line with a single integer that is the sum of all the volumes of the conversing cows.

Sample Input

4
3 1
2 5
2 6
4 3

Sample Output

57

Source

USACO 2004 U S Open

传送门:POJ 1990 MooFest

题目大意:给你n头牛,每头牛有一个分贝值以及坐标。每两头牛之间的权值为它们间的最大分贝值*距离。
问所有牛之间的权值和为多少?

题目分析:我们可以知道,对于每头牛,它的分贝值能产生影响价值的必定是存在比它分贝还小的牛。那么对此我们可以对牛按照分贝值做一次排序。
每次我们取一头牛i,价值为v,坐标为x,我们只要得到在该头牛坐标左边有多少牛dl以及左边的牛的距离之和xl,以及右边有多少牛dr及右边的牛的距离之和xr。那么由它产生的权值和即为v * (dl * x - xl + xr - dr * x) 。
我们该怎么得到dl,dr,xl,xr?
首先我们可以预处理出排序后的前i头牛的距离的前缀和xsum[i],以及在每头牛之前有多少头牛(这还用预处理?i-1就是了)。
假设我们已经处理到了第i头牛,在该头牛左边的牛的数量以及左边的牛的距离和用树状数组的向右add更新,那么通过向左求sum可以得到左边的牛的数量dl以及左边的牛的距离和xl。那么右边我们要做相同的处理吗?很显然不需要,因为右边的牛的数量dr就等于i-1-dl,右边的牛的距离和dr就等于前i-1头牛的距离和xsum[i - 1]-dl。
至此,便可以得到由该头牛产生的权值和。
问题解决。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

#define lowbit(I) ((I)&(-I))
#define clear( A , X ) memset ( A , X , sizeof A )

typedef long long BigInt ;

const int maxN = 20005 ;

struct Node {
	int x , v ;
	bool operator < ( const Node &t ) const {
		return v < t.v ;
	}
} ;

Node cow[maxN] ;
BigInt a[maxN] ;//数量
BigInt b[maxN] ;//距离
BigInt xsum[maxN] ;

BigInt sum ( int x , BigInt *arr ) {
	BigInt ans = 0 ;
	for ( int i = x ; i ; i -= lowbit ( i ) ) ans += arr[i] ;
	return ans ;
}

void add ( int x , int v , int n , BigInt *arr ) {
	for ( int i = x ; i <= n ; i += lowbit ( i ) ) arr[i] += v ;
}

void work () {
	int n , dist ;
	BigInt ans ;
	xsum[0] = 0 ;
	while ( ~scanf ( "%d" , &n ) ) {
		dist = ans = 0 ;
		for ( int i = 1 ; i <= n ; ++ i ) {
			scanf ( "%d%d" , &cow[i].v , &cow[i].x ) ;
			if ( cow[i].x >= dist ) dist = cow[i].x ;
		}
		sort ( cow + 1 , cow + n + 1 ) ;
		clear ( a , 0 ) ;
		clear ( b , 0 ) ;
		for ( int i = 1 ; i <= n ; ++ i ) xsum[i] = xsum[i - 1] + cow[i].x ;
		for ( int i = 1 ; i <= n ; ++ i ) {
			BigInt dl = sum ( cow[i].x , a ) ;
			BigInt dr = i - 1 - dl ;
			BigInt xl = sum ( cow[i].x , b ) ;
			BigInt xr = xsum[i - 1] - xl ;
			//printf ( "%d %d %d %d\n" , dl , dr , xl , xr ) ;
			ans += cow[i].v * ( dl * cow[i].x - xl ) ;
			ans += cow[i].v * ( xr - dr * cow[i].x ) ;
			add ( cow[i].x , 1 , dist , a ) ;
			add ( cow[i].x , cow[i].x , dist , b ) ;
		}
		printf ( "%lld\n" , ans ) ;
	}
}

int main () {
	work () ;
	return 0 ;
}


你可能感兴趣的:(poj,树状数组)