题目大意:有N(1<=N<=20000)头牛,每头牛有一个听力值和位置,它们要对话则要发出听力值较大的那一头牛的听力值乘它们的距离的声音,求任意两头牛都对话的所有声音和。
要求所有的声音和,那么每次对话只基于一头牛求就可以,可以基于听力值大的那头牛,首先对所有牛排序,根据听力值的大小。排序之后,每头牛只用求和在它前面的牛对话发出的声音,所有这样的声音加起来就是答案所求。
用两个树状数组来完成这个操作。对于每头牛,关于它的和分两部分求,第一部分是位置小于它的,第二部分是位置大于它的。第一个树状数组来存每头牛的位置,第二个树状数组来存位置在某个点是否有牛。即每次考虑完一个牛后,假设位置是u,则完成BIT1_add(u,u),BIT2_add(u,1)两个操作。第二个树状数组可以指示有多少头牛在当前牛的前面,第一个树状数组用于计算。
挺难表述,详见代码,关键代码就是主函数中最后一个for循环的那几行代码。。
#include<stdio.h>
#include<stdlib.h>
typedef long long LL;
typedef struct
{
int vol;
int loc;
}Cow;
Cow a[20010];
int b[35];
LL c[33000];
int e[33000];
int max;
LL BIT_sum(int x);
int BIT_sum2(int x);
void BIT_add(int x,int u);
void BIT_add2(int x,int u);
int Cmpa(const Cow*i,const Cow*j);
int main(void)
{
int i,j,u,v,n;
LL p,q,sum;
b[1]=1;
for(i=2;i<=30;i++)
{
b[i]=2*b[i-1]+1;
}
while(scanf("%d",&n)==1)
{
max=1;
for(i=1;i<=n;i++)
{
scanf("%d%d",&a[i].vol,&a[i].loc);
if(a[i].loc>max)
{
max=a[i].loc;
}
}
if(n==1)
{
printf("0\n");
}
else
{
j=1;
while(b[j]<max)
{
j++;
}
max=b[j];
for(i=1;i<=max;i++)
{
c[i]=e[i]=0;
}
qsort(a+1,n,sizeof(a[1]),Cmpa);
sum=0;
for(i=1;i<=n;i++)
{
u=a[i].loc;
v=a[i].vol;
p=BIT_sum2(u-1);
q=BIT_sum(u-1);
sum=sum+(LL)v*(p*u-q+(BIT_sum(max)-q)-(i-1-p)*u);
BIT_add(u,u);
BIT_add2(u,1);
}
printf("%lld\n",sum);
}
}
return 0;
}
LL BIT_sum(int x)
{
LL ret=0;
while(x>0)
{
ret=ret+c[x];
x=x-(x&-x);
}
return ret;
}
void BIT_add(int x,int u)
{
while(x<=max)
{
c[x]=c[x]+u;
x=x+(x&-x);
}
}
int BIT_sum2(int x)
{
int ret=0;
while(x>0)
{
ret=ret+e[x];
x=x-(x&-x);
}
return ret;
}
void BIT_add2(int x,int u)
{
while(x<=max)
{
e[x]=e[x]+u;
x=x+(x&-x);
}
}
int Cmpa(const Cow*i,const Cow*j)
{
return (*i).vol-(*j).vol;
}