Description
每一年,约翰的N(1≤N≤20000)只奶牛参加奶牛狂欢节.这是一个全世界奶牛都参加的大联欢.狂欢节包括很多有趣的活动,比如干草堆叠大赛、跳牛栏大赛,奶牛之间有时还相互扎屁股取乐.当然,她们会排成一列嚎叫,来欢庆她们的节日.奶牛们的叫声实在刺耳,以致于每只奶牛的听力都受到不同程序的损伤.现在告诉你奶牛i的听力为vi(l≤Vi≤20000),这表示如果奶牛j想说点什么让她听到,必须用高于vi×dis(i,j)的音量.而且,如果奶牛i和j想相互交谈,她们的音量必须不小于max(Vi,Vj)×dis(i,j).其中dis(i,J)表示她们间的距离.
现在N只奶牛都站在一条直线上了,每只奶牛还有一个坐标xi(1≤xi≤20000).如果每对奶牛都在交谈,并且使用最小音量,那所有n(n-1)/2对奶牛间谈话的音量之和为多少?
Input
第1行输入N,之后N行输入Vi和xi.
Output
输出音量之和.
Sample Input
4
3 1
2 5
2 6
4 3
Sample Output
57
解题思路
将奶牛按vi值从小到大排序,然后枚举每一个奶牛,用他的vi值乘上排序后排在他前面所有奶牛与他的距离之和,加到答案里。
这里求距离和的时候需要用到两个树状数组,第i项分别表示坐标小于i的奶牛数量和所有坐标小于i的奶牛坐标之和。
这样,在枚举每个奶牛的时候就可以利用两数组记录的值快速求解答案。
代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<cstdlib>
#define ll long long
using namespace std;
ll n,lo,mx=0,ans=0;
struct ldy
{
ll v,x;
}s[20005];
struct ldx
{
ll a[20005];
void add(ll x,ll num)
{
while(num<=lo)
{
a[num]+=x;
num+=num&(-num);
}
}
ll ch(ll num)
{
ll j=0;
while(num>0)
{
j+=a[num];
num-=num&(-num);
}
return j;
}
}p,q;
bool cmp(ldy a,ldy b) {return a.v<b.v;}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&s[i].v,&s[i].x);
lo=max(lo,s[i].x);
}
sort(s+1,s+n+1,cmp);
for(int i=1;i<=n;i++)
{
ll r1=p.ch(s[i].x);
ll r2=q.ch(s[i].x);
ll r3=p.ch(mx)-r1;
ll r4=q.ch(mx)-r2;
mx=max(s[i].x,mx);
p.add(1,s[i].x);
q.add(s[i].x,s[i].x);
if(r1!=0) ans+=(r1*s[i].x-r2)*s[i].v;
if(r3!=0) ans+=(r4-r3*s[i].x)*s[i].v;
}
printf("%lld",ans);
return 0;
}