您的位置:首页 > Web前端

【poj 1990】MooFest(树状数组)

2017-10-03 22:40 316 查看
传送门biu~

题目大意:一群牛站成一条直线,第i头牛听见别人的讲话,别人的音量必须大于v[i]。两头牛i、j必须用同一个声音max(v[i],v[j])交流。消耗的能量为 声音大小*他们之间的距离。现在有n头牛,给定n头牛的v[i]和坐标,求他们之间两两交流所需要的能量和。

思路:把每头牛按v值大小排序。逐一加入时,第i头牛与第1~(i-1)头牛交流的声音大小一定是v[i]。这样就用树状数组numtree维护有多少头牛,用loctree维护牛的坐标和,用tot维护当前已加入的所有的牛的坐标和。

所以对于牛i,他前面有num头牛,这些牛的坐标和为loc,第i头牛的坐标为xi,声音v值为vi。那么它和比它坐标小的牛之间的坐标差front=num*xi-loc;它和比他坐标大的牛之间的坐标差back=(tot-loc-xi)-xi(i-num-1)。

最后让ans的值加上v[i]*(front+back)就可以了。

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define MAXN 20005
#define ll long long
using namespace std;
struct COW{
int v,x;
}a[MAXN];
inline bool cmp(COW a,COW b){return a.v<b.v;}
ll numtree[MAXN],loctree[MAXN],n;
int Nmax;
inline void add(ll *a,int x,int num)
{
while(x<=Nmax)
{
a[x]+=num;
x+=lowbit(x);
}
}
inline ll search(ll *a,int x)
{
ll re=0;
while(x)
{
re+=a[x];
x-=lowbit(x);
}
return re;
}
int main()
{
while(~scanf("%d",&n))
{
ll ans=0,tot=0;
memset(numtree,0,sizeof(numtree));
memset(loctree,0,sizeof(loctree));
Nmax=0;
for(int i=1;i<=n;++i)
{
scanf("%d%d",&a[i].v,&a[i].x);
Nmax=max(a[i].x,Nmax);
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;++i)
{
add(numtree,a[i].x,1);
add(loctree,a[i].x,a[i].x);
tot+=a[i].x;
ll num=search(numtree,a[i].x-1);
ll loc=search(loctree,a[i].x-1);
ll front=num*a[i].x-loc;
ll back=(tot-loc-a[i].x)-a[i].x*(i-num-1);
ans+=a[i].v*(front+back);
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: