超級傳送門:http://poj.org/problem?id=1990
題意:X軸上有N頭牛(1<=N<=20000),每頭牛有一個聽力值v[i]和唯一的橫座標x[i]。兩頭牛直接互相通話的花費定義爲max(v[i],v[j])*abs(x[i]-x[j]),現在要求輸出所有牛互相通話的總花費。
分析:用兩個樹狀數組,一個用來存放當前位置左側牛的個數,另一個存放左側牛的橫座標。利用排序可以巧妙地避開max(v[i],v[j])的計算,先按照v從小到大對牛排序然後再依次插入樹狀數組,不影響結果。這樣的話每次計算左側的時候,乘以的v都是當前牛的v(當前最大)。
在紙上畫個圖就能看出其關係:
左側牛到當前牛距離和 = 左側牛數量 * X - 左側牛座標和
右側牛到當前牛距離和 = 右側牛座標和 - 右側牛數量 * X
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 20010;
struct node {
int x,v;
}cow[maxn];
int c1[maxn]; //樹狀數組1:記錄牛的個數
int c2[maxn]; //樹狀數組2:記錄牛的x座標
int n;
int cmp(const struct node& a,const struct node& b) {
if (a.v!=b.v) return a.v<b.v;
return a.x<b.x;
}
int lowbit(int t) {
return t & -t;
}
__int64 getsum1(int end) {
__int64 ret=0;
for (int i=end;i>=1;i-=lowbit(i)) {
ret += c1[i];
}
return ret;
}
void update1(int p,int val) {
for (int i=p;i<maxn;i+=lowbit(i)) {
c1[i] += val;
}
}
__int64 getsum2(int end) {
__int64 ret=0;
for (int i=end;i>=1;i-=lowbit(i)) {
ret += c2[i];
}
return ret;
}
void update2(int p,int val) {
for (int i=p;i<maxn;i+=lowbit(i)) {
c2[i] += val;
}
}
int main () {
#ifndef ONLINE_JUDGE
freopen("1.txt","r",stdin);
#endif
int n;
__int64 ans;
while (scanf("%d",&n)>0) {
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
ans = 0;
for(int i=1;i<=n;i++) {
scanf("%d%d",&cow[i].v,&cow[i].x);
}
sort(cow+1,cow+n+1,cmp);
for(int i=1;i<=n;i++) {
update1(cow[i].x,1);
update2(cow[i].x,cow[i].x);
ans += cow[i].v*( getsum1(cow[i].x-1)*cow[i].x //左側牛數量 * X
- getsum2(cow[i].x-1) //左側牛座標和
+ getsum2(maxn-1) - getsum2(cow[i].x) //右側牛座標和
- ( getsum1(maxn-1)-getsum1(cow[i].x) )*cow[i].x ); //右側牛數量 * X
/*
左側牛到當前牛距離和 = 左側牛數量 * X - 左側牛座標和
右側牛到當前牛距離和 = 右側牛座標和 - 右側牛數量 * X
*/
}
printf("%I64d\n",ans);
}
return 0;
}