POJ 1990 MooFest (树状数组)

来源:互联网 发布:网络捕鱼游戏加盟代理 编辑:程序博客网 时间:2024/05/17 03:52
每年,农夫约翰的N(1 <= N <= 20,000)只牛会参加“MooFest”,一个来自世界各地的牛的社交聚会。 MooFest有许多活动,包括干草堆积,篱笆跳跃,把尾巴钉在农夫的身上...当奶牛都站在同一个地方排队,他们会大声喊叫,吼声几乎震耳欲聋。事实上,每年参加了这个活动后,一些奶牛已经失去了部分听力。 

每个奶牛具有耳背值v(i)(在1..20,000的范围内)。如果一头牛向牛i吼叫,她必须使用至少是两头母牛之间距离的v(i)倍的声音,以便被牛i听到。如果两个奶牛i和j想要交谈,她们必须以等于她们之间的距离乘以max(v(i),v(j))的音量说话。 

假设N头奶牛中的每头奶牛都站在直线上(每头奶牛在1..20,000范围内的某个独特x坐标),每对奶牛都使用尽可能小的声音进行谈话。 

计算所有N(N-1)/ 2对正在说话的奶牛产生的所有声音的总和。 
Input
*第1行:单个整数,N 

*第2到N + 1行:两个整数:牛的耳背值v和x坐标。第2行代表第一头牛;第3行表示第二头牛;等等。没有两头牛会站在同一个位置。 
Output
*第1行:仅含单个整数,表示所有牛互相吼叫的所有声音的总和。 
Sample Input
43 12 52 64 3
Sample Output

57


思路:当两头牛进行计算时,用到的是V值大的牛。所以先按照V值从大到小排序,当计算某头牛时,只考虑V值比它小的那些牛。我们用两个树状数组分别表示牛的坐标之和及牛的数量之和(以坐标作为数组下标)。那么考虑牛i时(按V从大到小排序后),设坐标值比它小的那些牛的数目为num1、坐标之和为sum1,坐标值比它大的那些牛的数目为num2、坐标之和为sum2,那么对该牛而言(设坐标为X,体力值为V),所贡献的答案为V * ( X*num1-sum1 + sum2-X*num2 )。


#include<cstdio>#include<cstring>#include<vector>#include<map>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int maxn = 20000 + 10;struct Node {  int x, v;  bool operator < (const Node& rhs) const {    return v > rhs.v;  }}p[maxn];int C1[maxn], C2[maxn], n, mx;int lowbit(int x) {  return x & -x;}int Sum(int *a, int x) {  int ans = 0;  while(x > 0) {    ans += a[x];    x -= lowbit(x);  }  return ans;}void add(int *a, int x, int v) {  while(x < maxn) {    a[x] += v;    x += lowbit(x);  }}int main() {  scanf("%d", &n);    for(int i = 1; i <= n; i++) {    scanf("%d%d", &p[i].v, &p[i].x);    add(C1, p[i].x, p[i].x);    add(C2, p[i].x, 1);  }  sort(p+1, p+n+1);    ll ans = 0;  for(int i = 1; i < n; i++) {    add(C1, p[i].x, -p[i].x);    add(C2, p[i].x, -1);    int sum1 = Sum(C1, p[i].x);    int num1 = Sum(C2, p[i].x);    int sum2 = Sum(C1, mx) - sum1;    int num2 = Sum(C2, mx) - num1;    ans += (ll)(p[i].x * num1 - sum1 + sum2 - p[i].x * num2) * (ll)(p[i].v);  }    printf("%lld\n", ans);  return 0;}


0 0