MooFest POJ1990
题意:大概就有一堆点,点有权值,求每对点的max(权值)*距离只和
思路:按权值从小到大排序后存入,因为从小到大,所以每次存入的时候都是当前权值为最大,将它与前后的距离相乘
用树状数组维护两个值,一个是存坐标和(距离原点),一个是存数目
每次存入点时,坐标的左边坐标和就是x*sum(x,num)-sum(x,pos)
同理右边也是,然后得到的值相加再乘权值
代码:
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn=20000+5;
struct node
{
int x,v;
}cow[maxn];
long long pos[maxn]; //坐标和(和0比)
long long num[maxn]; //比当前坐标小的牛的个数
bool comp(node a,node b)
{
if(a.v<b.v) return true;
else return false ;
}
int lowbit(int x) //算最低位1的值
{
return x&-x;
}
void update(int k,int a,long long b[]) //更新树状数组c[k]
{
for(;k<=maxn;b[k]+=a,k+=lowbit(k));
}
long long sum(int k,long long b[]) //一维计算1-k
{
long long res=0;
for(;k>0;res+=b[k],k-=lowbit(k));
return res;
}
long long sum(int l,int k,long long b[]) //一维计算l-k
{
return sum(k,b)-sum(l,b);
}
int main()
{
long long n,x,v;
long long ans=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>v>>x;
cow[i].v=v;
cow[i].x=x+1; //树状数组防0
}
sort(cow+1,cow+1+n,comp);
for(long long i=1;i<=n;i++)//num数组是存个数,pos数组存的是坐标离远点的和
{
long long left ,right; //x前后的坐标和
left=sum(cow[i].x,num)*cow[i].x-sum(cow[i].x,pos); //当前x前面有几个坐标存入*x-x前面的所有坐标和
right=sum(cow[i].x,maxn,pos)-(i-1-sum(cow[i].x,num))*cow[i].x; //x后面的所有坐标和-(x后面有几个坐标)*x
ans += (left + right) * cow[i].v; //需要的值
update(cow[i].x,cow[i].x,pos); //更新坐标值总和
update(cow[i].x,1,num) ; //更新0~当前坐标个数和
//cout<<ans<<endl;
}
printf("%lld\n", ans);;
return 0;
}