題意:
- 有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;
}