题目:http://poj.org/problem?id=1990
题意:n个耳背的奶牛,第i个奶牛听到声音需要v[i]的分贝,站在x[i]位置的直线上,两个奶牛之间对话的音量是max(v[i],v[j])*两者之间的距离,问所有奶牛互相可以听到的音量和。
思路:将所有奶牛按照可听到音量的大小进行排序,两只奶牛对话所需的分贝就是排在后面的奶牛的 v,所以排在后面的奶牛对排在前面的奶牛对话的音量就可以求了。
第 i个奶牛的分贝是 v[i],设所有分贝排在他前面的奶牛有m个,所以与其中站在它前面的奶牛,每对所需音量:
(x-x1)*f, (x-x2)*f,...,x是第i个奶牛的位置,其他是站在前面且排在前面的奶牛位置,所以加起来就是(cnt*x-sum)*f,cnt是排且站在前面的奶牛个数,sum是他们的位置和。 树状数组维护cnt和sum。
剩下站在后面的奶牛是(x1-x)*f, (x2-x)*f,...,加起来就是(all - sum -(i-1-cnt)*x)*f, all是所有排在前面的奶牛位置和,sum就是上面的sum,all-sum是(x1+x2+...),i就是加入到第i个奶牛,(i-1-cnt)就是排在i前面但位置在后面的奶牛个数。
所以就出来了 ans += (cnt*x-sum+all - sum -(i-1-cnt)*x) * f。
一边算一边加入,最后就会把所有 n*(n-1)/2对奶牛算完。
记得 long long,wa了好几发,还由于把n的输入格式写错,wa了(捂脸。
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 2e4 + 10;
struct cow
{
ll vol,pos;
bool operator<(const cow &a)const //第一次用构造函数,记得,记得,记得return和两个const
{
return vol < a.vol;
}
}cows[maxn];
ll sum[maxn],cont[maxn];
ll lowbit(int x)
{
return x&(-x);
}
void update(int x,ll d,bool flag)
{
while(x < maxn)
{
if(flag) cont[x]++;
else sum[x] += d;
x += lowbit(x);
}
}
ll query(int x,bool flag)
{
ll res = 0;
while(x > 0)
{
if(flag) res += cont[x];
else res += sum[x];
x -= lowbit(x);
}
return res;
}
int main()
{
ll ans = 0;
int n;
scanf("%d",&n);
for(int i=1; i<=n; ++i)
{
scanf("%lld%lld",&cows[i].vol,&cows[i].pos);
}
sort(cows+1,cows+n+1);
for(int i=1; i<=n; ++i)
{
ll sum = query(cows[i].pos,0),cnt = query(cows[i].pos,1),all = query(maxn,0);
ans += cows[i].vol*(cnt * cows[i].pos - sum + all - sum - (i - 1 - cnt) * cows[i].pos);
updata(cows[i].pos,0,true);
updata(cows[i].pos,cows[i].pos,false);
}
printf("%lld\n",ans);
return 0;
}