http://poj.org/problem?id=1990
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头牛的听力v[i]. 现在规定两头你i和j如果要进行交流的话那么消耗的能量就是dis(i,j)*max(v[i],v[j]),现在问n头牛总共的n(n-1)*2种方式消耗的总的能量。
思路:暴力枚举会TLE,我们需要一种更高效的方法。因为对于第i头牛和第j头牛来说消耗的能量和max(v[i],v[j])有关系,因此我们考虑把牛按照听力从小到大排序,这样方便我们计算。排序后开始遍历序列,设我们当前要计算第i头牛的贡献,我们已知以下数据:
规定:
a
[
i
]
.
p
o
s
表
示
第
i
头
牛
的
坐
标
a
[
i
]
.
v
表
示
第
i
头
牛
的
体
积
a[i].pos表示第i头牛的坐标\quad a[i].v表示第i头牛的体积
a[i].pos表示第i头牛的坐标a[i].v表示第i头牛的体积已知:
t
m
p
1
=
前
i
−
1
头
牛
中
坐
标
<
a
[
i
]
.
p
o
s
的
牛
的
个
数
tmp1=前i-1头牛中坐标<a[i].pos的牛的个数
tmp1=前i−1头牛中坐标<a[i].pos的牛的个数
t
m
p
2
=
前
i
−
1
头
牛
中
坐
标
<
a
[
i
]
.
p
o
s
的
牛
的
坐
标
之
和
tmp2=前i-1头牛中坐标<a[i].pos的牛的坐标之和
tmp2=前i−1头牛中坐标<a[i].pos的牛的坐标之和
t
o
t
=
前
i
−
1
头
牛
的
坐
标
之
和
tot=前i-1头牛的坐标之和
tot=前i−1头牛的坐标之和那么我们可以推得:
t
m
p
3
=
t
o
t
−
t
m
p
2
=
前
i
−
1
头
牛
中
坐
标
>
a
[
i
]
.
p
o
s
的
牛
的
坐
标
之
和
tmp3=tot-tmp2=前i-1头牛中坐标>a[i].pos的牛的坐标之和
tmp3=tot−tmp2=前i−1头牛中坐标>a[i].pos的牛的坐标之和
t
m
p
4
=
i
−
t
m
p
1
=
前
i
−
1
头
牛
中
坐
标
>
a
[
i
]
.
p
o
s
的
牛
的
个
数
tmp4=i-tmp1=前i-1头牛中坐标>a[i].pos的牛的个数
tmp4=i−tmp1=前i−1头牛中坐标>a[i].pos的牛的个数我们分成两部分计算贡献:
坐
标
<
a
[
i
]
.
p
o
s
的
牛
的
贡
献
=
a
[
i
]
.
v
∗
(
a
[
i
]
.
p
o
s
∗
t
m
p
1
−
t
m
p
2
)
坐标<a[i].pos的牛的贡献=a[i].v*(a[i].pos*tmp1-tmp2)
坐标<a[i].pos的牛的贡献=a[i].v∗(a[i].pos∗tmp1−tmp2)
坐
标
>
a
[
i
]
.
p
o
s
的
牛
的
贡
献
=
a
[
i
]
.
v
∗
(
t
m
p
3
−
a
[
i
]
.
p
o
s
∗
t
m
p
4
)
坐标>a[i].pos的牛的贡献=a[i].v*(tmp3-a[i].pos*tmp4)
坐标>a[i].pos的牛的贡献=a[i].v∗(tmp3−a[i].pos∗tmp4)现在已经知道怎么计算答案了,关键在于如何求tmp1和tmp2,其实很简单,用两个树状数组分别维护tmp1和tmp2就好了。详情见代码。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e4+5;
const int MAX=2e4;
struct node
{
int pos,v;
bool operator <(const node &a)const
{
if(v==a.v)
return pos<a.pos;
return v<a.v;
}
};
int n;
node a[maxn];
ll tree1[maxn];// 坐标<=i 的牛的个数
ll tree2[maxn];//坐标<=i 的牛的坐标之和
inline int lowbit(int x)
{
return x&(-x);
}
inline void add1(int i,int v)
{
for(;i<=MAX;i+=lowbit(i))
tree1[i]+=v;
}
inline void add2(int i,int v)
{
for(;i<=MAX;i+=lowbit(i))
tree2[i]+=v;
}
inline ll sum1(int i)
{
ll ans=0;
for(;i;i-=lowbit(i))
ans+=tree1[i];
return ans;
}
inline ll sum2(int i)
{
ll ans=0;
for(;i;i-=lowbit(i))
ans+=tree2[i];
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&a[i].v,&a[i].pos);
sort(a,a+n);
ll tot=0,ans=0,tmp1,tmp2,tmp3,tmp4;
for(int i=0;i<n;i++)
{
tmp1=sum1(a[i].pos);//坐标小于 第i头牛的个数
tmp2=sum2(a[i].pos);//坐标小于 第i头牛的坐标之和
tmp3=tot-tmp2;//坐标大于 第i头牛的坐标之和
tmp4=i-tmp1;//坐标大于 第i头牛的个数
ans+=a[i].v*(a[i].pos*tmp1-tmp2)+a[i].v*(tmp3-a[i].pos*tmp4);
add1(a[i].pos,1);
add2(a[i].pos,a[i].pos);
tot+=a[i].pos;
}
printf("%lld\n",ans);
return 0;
}