这是接触的第一道树状数组题。。想了比较长的时间。。最后网上找的一下思路。。是道很好的题。。以后要复习一下。。
题目大意:
有 N 头牛,每头牛位于 第 Xi 位 且只有叫它声音高于 Vi 他才听得见,而牛之间交流消耗的能量 譬如第 i 头和第 j 头交流 消耗能量为 max(vi,vj)*( | xi - xj | )
首先 我们要优先去看那些失聪程度大的牛,比如当前为 第 K 头,那么当任意牛 i 的Vi 小于 Vk 时,我们以 Vk 为准,所以可以先按 V 排序,那么我们只需要在对牛遍历是 看距离就可以了
接下来公式为 *vi 就可以了 由于数据原因。本题直接暴力去算会超时,我们这时候便可以用 BIT 优化 最终解决。
因为排完序之后 完全无需去看 v 只需要最后计算的时候 把它乘上即可,我们开两个 树状数组 一个维护 比当前牛距离小的牛的个数,另一个维护比当前牛距离小的牛的坐标。
至于计算公式,我们可以用 sum( xi ) 求出比当前牛位置小的牛的位置, 可以用 sum( maxn )求出加入数组内所有牛的坐标和,经过计算 我们还知道目前放入数组一共有几头牛,那么根据公式进行加减便可以求出了
以下为AC 代码(这道题真的不适合刚刚学树状数组的人去做)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
struct node
{
ll f,x;
} s[20010];
bool cmp(node a,node b)
{
return a.f<b.f;
}
int n;
ll c1[20010],c2[20010];
ll lowbit(ll k)
{
return k&(-k);//二进制末尾的 1 的十进制数
}
void add1(ll k,ll num)
{
while (k<20010)
{
c1[k]+=num;
k+=lowbit(k);
}
}
void add2(ll k,ll num)
{
while (k<20010)
{
c2[k]+=num;
k+=lowbit(k);
}
}
ll sum1(ll k)
{
ll sm=0;
while (k)
{
sm+=c1[k];
k-=lowbit(k);
}
return sm;
}
ll sum2(ll k)
{
ll sm=0;
while (k)
{
sm+=c2[k];
k-=lowbit(k);
}
return sm;
}
int main()
{
while (~scanf("%d",&n))
{
for (int i=1; i<=n; i++)
{
scanf("%lld%lld",&s[i].f,&s[i].x);
}
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
sort(s+1,s+n+1,cmp);
ll ans=0;
for (int i=1; i<=n; i++)
{
add1(s[i].x,1);
add2(s[i].x,s[i].x);//维护更新两个数组
ll nn=sum1(s[i].x);//个数
ll sss=sum2(s[i].x);//坐标
ans+=(nn*s[i].x-sss)*s[i].f;//得到的是在当前x前面所有坐标小于他的牛
ll nnn=i-nn;
ll ss=sum2(20000)-sss;//总共的减去比较近的等于比较远的
ans+=(ss-s[i].x*nnn)*s[i].f;//在他前面的比他坐标值大的x
}
printf ("%lld\n",ans);
}
return 0;
}