您的位置:首页 > Web前端

(POJ 1990)MooFest 树状数组 求一个数和他前面的所有数的值的差值之和

2017-05-29 22:18 495 查看
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


题意: 

有n头牛站成一排,编号从1到n。   每头牛有两个属性x和v;

任意两头牛a,b之间存在一个数等于 abs ( x[a] - x ) * max( v[a], v[b]);

让你求所有的这些数的和。

[b]思路:


因为要求所有的两头牛,所以我们就不用管谁是第一头,谁是最后一头了。

然而看起来很繁琐啊,我们可以选择对这些智障牛进行排序;

那么问题来了,按照什么标准来排序呢?

如果按照x排序,那你这辈子可算有事儿做了;

如果按照v从小到大排序,那么v[i] 之前的牛都比v[i] 小,那么我们就简化了比较大小的部分,只需要求 i 之前的牛和这头牛的距离(这里指绝对值)和 。然后用这个和乘v[i] 就求出与这头牛有关的了,然后按照顺序处理其他的牛,问题就得到解决了。

设排序后的某牛op[i]之前x 小于 op[i].x 的牛的数量为 cnt[i];

那么 i 之前x大于op[i].x的牛的数量为 i-1-cnt[i];

设 i 之前x 小于op[i].x的  牛的x总和为 pre[i];

那么i 之前x大于op[i].x的牛的x总和为zong[i-1] - pre[i];

设i之前所有的x和为zong[i];

那么我们就可以得到式子:

(cnt[i]*op[i].x - pre[i])*op[i].v +(zong[i-1]-pre[i]-(i-1-cnt[i])*op[i].x)*op[i].v;

所以我们只需要用树状数组处理cnt和pre就可以解决问题了。

上代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int cnt[20001];
int pre[20001];
int zong[20001];
int ans[20001];
int pree[20001];
int n;
struct node
{
int v;
int x;
};
node op[20001];
int maxn_ans;
bool cmp(node a,node b)
{
return a.v < b.v;
}
int getf(int x)
{
return x&(-x);
}
void add_ans(int x)
{
while(x<=maxn_ans)
{
ans[x]++;
x += getf(x);
}
return ;
}
int get_sum_ans(int x)
{
int sum1 = 0;
while(x>0)
{
sum1 += ans[x];
x -= getf(x);
}
return sum1;
}
void add_pree(int x)
{
int t = x;
while(x<=maxn_ans)
{
pree[x] += t;
x += getf(x);
}
return ;
}
int get_sum_pree(int x)
{
int sum1 = 0;
while(x>0)
{
sum1 += pree[x];
x -= getf(x);
}
return sum1;
}
int main()
{
scanf("%d", &n);
memset(cnt,0,sizeof(cnt));
memset(pre,0,sizeof(pre));
memset(op, 0,sizeof(op));
memset(zong,0,sizeof(zong));
memset(ans,0,sizeof(ans));
memset(pree,0,sizeof(pree));

for(int i=1;i<=n;i++)

4000
{
scanf("%d %d",&op[i].v, &op[i].x);
maxn_ans = max(maxn_ans,op[i].x);
}

sort(op+1,op+1+n,cmp);

for(int i=1;i<=n;i++)
{
zong[i] = zong[i-1] + op[i].x;
cnt[i] = get_sum_ans(op[i].x-1);
add_ans(op[i].x);

pre[i] = get_sum_pree(op[i].x-1);
add_pree(op[i].x);
}

long long sum = 0;
for(int i=1;i<=n;i++)
{
sum += (long long)(cnt[i]*op[i].x - pre[i])*op[i].v + (long long)(zong[i-1]-pre[i]-(i-1-cnt[i])*op[i].x)*op[i].v;
}

printf("%lld\n",sum);

return 0;
}
水波。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树状数组两个