题意:
- 有n头牛在x轴上,每头牛具有两个属性,听力值vi和坐标xi,两头牛i,j沟通需要消耗 max(vi,vj) * abs(xi-xj)
- 现在问你所有任意两头牛所需要消耗的总值,共n*(n-1)/2种
做法:
- 首先暴力肯定是不行滴~
- 我们为了优化计算,我们可以先根据牛的听力值从小到大排序。
- 那么 ans = v1*(第1头牛与其他牛的距离差的和)+v2*(第2头牛与其他牛的距离差的和)+……+vn(第n头牛与其他牛的距离差的和)
- 现在要优化怎么计算距离差的和的问题
- 以题中的样例为例,我们排完序后为
- V: 2 2 3 4
- X: 5 6 1 3
- 我们发现有一些牛的前面的牛 有坐标比它小的,也有比它大的。我们需要把这左右两边都计算好距离差才行。
- 当前这头牛的坐标如果是1,它前面没有比它更小的坐标了,即0头,但有比它的坐标大 有 3-1-0头,即这是第三头牛,去掉他自己,比它大的有2头,距离差的和就是 6 - 1+ 5-1 = 11 - 2*1 = 9
- 当前的这头牛的坐标如果是3 ,他前面有比它小的牛的坐标和是1,且有着1头,那么3*1(头) - 1(前面坐标比当前牛小的坐标和) = 2 即它与左边比它小的坐标的坐标差的和。
- 它前面坐标比它大的有 4 - 1 - 1 = 2 头牛,它与这两头牛的坐标差的和 = 5+6+1 - 1 - 2*3 = 5
- 我们发现我们可以维护什么呢?对! 坐标和和牛的头数,这样我们就可以是用树状数组了
AC代码:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <ctime>
#define IO ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x) push_back(x)
#define sz(x) (int)(x).size()
#define sc(x) scanf("%d",&x)
#define pr(x) printf("%d\n",x)
#define abs(x) ((x)<0?-(x):x)
#define all(x) x.begin(),x.end()
#define debug printf("!!!!!!\n")
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const double PI = 4*atan(1.0);
const int maxm = 1e8+5;
const int maxn = 2e4+5;
const int INF = 0x3f3f3f3f;
int n,m;
struct node
{
int val;
int pos;
}cow[maxn];
int tree[2][maxn];//维护两个树状数组
inline ll read()
{
char x;
int flag = 0;
while(x = getchar(),x<'0' || x>'9') if(x == '-') flag = 1;
ll u = x-'0';
while(x = getchar(),x>='0' && x<='9') u = (u<<3)+(u<<1)+x-'0';
if(flag) u = -u;
return u;
}
inline ll lowbit(ll x){return x&(-x);}
void update(ll x,ll val,int flag)
{
for(ll i=x;i<=maxn;i+=lowbit(i)) tree[flag][i]+=val;
}
ll query(ll x,int flag)
{
ll res = 0;
for(int i=x;i;i-=lowbit(i)) res+=tree[flag][i];
return res;
}
bool cmp(node a,node b)
{
if(a.val == b.val) return a.pos<b.pos;
else return a.val<b.val;
}
int main()
{
#ifdef LOCAL_FILE
freopen("in.txt","r",stdin);
#endif // LOCAL_FILE
n = read();
for(int i=1;i<=n;i++)
{
cow[i].val = read();
cow[i].pos = read();
}
sort(cow+1,cow+1+n,cmp);
ll res = 0;
for(int i=1;i<=n;i++)
{
ll num = query(cow[i].pos,0); //表示比当前的牛pos小的有几头
ll prep = query(cow[i].pos,1);//表示比当前的牛pos小的牛的pos和
ll l = num*cow[i].pos-prep; //当前牛与其pos前面的差值
ll r = query(maxn,1)-prep-(i-1-num)*cow[i].pos; //当前牛与其pos后面的差值
res += (l+r)*cow[i].val;
update(cow[i].pos,1,0);
update(cow[i].pos,cow[i].pos,1);
}
printf("%lld\n",res);
#ifdef LOCAL_FILE
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // LOCAL_FILE
return 0;
}