题意:
有N头牛,每个有两个属性:距离和权值,任意两个都可以交流,两头牛交流的花费是其中权值较大的权值。问所有的牛可以两两交流,共需要花费多少权值。
题解:
按照V从小到大排序,当前处理的就是最大的。然后怎么去找在他之前的牛的d和在它之后的d呢?在它前面的d总和可以用树状数组标记法去求,在它之后的只需用当前处理的总距离减去前面的距离总和,就可以得到在它后面的距离总和。
开两个树状数组,第一个记录在牛x之前的数量,另一个记录在它之前的坐标总和。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 20111;
long long c[2][maxn];
struct node
{
int v,d;
bool operator <(const node& a)const
{
return v<a.v;
}
}ns[maxn];
void add(int i,int x,int v)
{
while(x<maxn)
{
c[i][x]+=v;
x+=(x & -x);
}
}
long long sum(int i,int x)
{
long long res=0;
while(x>0)
{
res+=c[i][x];
x-=(x&-x);
}
return res;
}
int main()
{
int n;
while(cin>>n)
{
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ns[i].v,&ns[i].d);
}
sort(ns+1,ns+1+n);
long long ans=0;
long long tot=0;//坐标和
for(int i=1;i<=n;i++)
{ int x=ns[i].d;
tot+=x;///总的坐标和
int s1=sum(0,x);//i之前有多少头
long long s2=sum(1,x);//i之前坐标和
long long q=s1*x-s2;//左边的坐标差
long long w=tot-x-s2-x*(i-1-s1);//右边的坐标差
ans+=(q+w)*ns[i].v;
add(0,x,1);
add(1,x,x);
}
cout<<ans<<endl;
}
}