MooFest POJ 1990 【树状数组】

来源:互联网 发布:淘宝暗黑3代练 编辑:程序博客网 时间:2024/05/17 06:35

MooFest

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 60000/30000K (Java/Other)

Problem 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 <br> <br>* 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. <br>
 

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

Sample Input
43 12 52 64 3
 

Sample Output
57
 

//题意:现在有很多头牛,每头牛有一个位置和一个耳聋程度,每头牛要和另外的所有牛说话(仅1次),每两头牛之间说话的声音必须是两者较大的那个耳聋度,要求距离*声音之和。

//思路:先把所有牛按耳聋程度排序(大->小),每次都选最聋的去和其他牛说话,这样,说话的声音就是这头牛的耳聋度(设为x)。设这头牛是第n个位置,总共有m个位置(输入的位置的最大值),每头牛的位置用dis1、dis2、...、dism表示,设该头牛前面共有num1头牛,后面共有num2头牛。

每头牛和另外所有牛说话的value=x*(dis(n+1)-dis(n)+dis(n+2)-dis(n)+...+dis(m)-dis(n))+x*(dis(n)-dis(1)+dis(n)-dis(2)+...+dis(n)-dis(n-1))=x*((dis(n+1)+dis(n+2)+...+dis(m))-num2*dis(n))+x*(num1*dis(n)-(dis(1)+dis(2)+...+dis(n-1)))

dis(n+1)+dis(n+2)+...+dis(m) 和dis(1)+dis(2)+...+dis(n-1)可以用一个树状数组解

num1、num2也可以用一个树状数组解

所以,这道题要用到2个树状数组!

(1)求num1、num2:

先设一个数组,大小为m。
有牛的位置设为1,没牛的位置设为0。套个树状数组模板(这里不解释了),num1=sum(n-1),num2=sum(m)-sum(n);每头牛结束后把它原来那个位置的值变成为0(即add(dis(n) , -1) ),因为1头牛只要跟其他牛说一次。


(2)求dis(n+1)+dis(n+2)+...+dis(m) 和dis(1)+dis(2)+...+dis(n-1):

再设一个数组,大小为m。
有牛的位置的值设为它的坐标,没牛的位置设为0。套个树状数组模板,dis(n+1)+dis(n+2)+...+dis(m) = sum(m)-sum(n);dis(1)+dis(2)+...+dis(n-1) = sum(n-1);每头牛结束后同样把它原来那个位置的值变成为0(即add(dis(n) , -dis(n)))。

最后用个ans,每次+=value就ok啦!上代码!

值可能非常大,尽量都用__int64,记得输入、输出的时候是%I64d ... 因为这个WA了2次— —!

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <cstdlib>#include <algorithm>using namespace std;const int MAX = 20010;typedef struct {__int64 x;__int64 num;}Cow;int n;int maxx;bool cmp(Cow p, Cow q){return p.num > q.num;}__int64 lowbit(__int64 x){return x&(-x);}void add(int k, __int64 x, __int64 c[]){while (k <= maxx){c[k] += x;k += lowbit(k);}}__int64 sum(int x, __int64 c[]){__int64 sum = 0;while (x > 0){sum += c[x];x -= lowbit(x);}return sum;}int main(){int i;while (scanf("%d", &n) != EOF){maxx = 0;__int64 c[MAX];// 位置__int64 a[MAX];// 0/1Cow s[MAX];memset(a, 0, sizeof(a));memset(c, 0, sizeof(c));for (i = 1; i <= n; i++){scanf("%I64d%I64d", &s[i].num, &s[i].x);if (s[i].x > maxx)maxx = s[i].x;}for (i = 1; i <= n; i++){add(s[i].x, 1, a);add(s[i].x, s[i].x, c);}sort(s + 1, s + n + 1, cmp);__int64 ans = 0;for (i = 1; i <= n; i++){//跟后面的牛说话__int64 temp1 = s[i].num*((sum(maxx, c) - sum(s[i].x, c)) - (sum(maxx, a) - sum(s[i].x, a))*s[i].x);//跟前面的牛说话__int64 temp2 = s[i].num*((sum(s[i].x - 1, a))*s[i].x - (sum(s[i].x - 1, c)));add(s[i].x, -1, a);add(s[i].x, -s[i].x, c);ans += (temp1 + temp2);}printf("%I64d\n", ans);}return 0;}