您的位置:首页 > Web前端

POJ 1990 MooFest【 树状数组 】

2015-06-29 18:52 459 查看
题意:给出n头牛,每头牛有一个听力v,坐标x,两头牛之间的能量为max(v1,v2)*dist(v1,v2),求总的能量值

先将每头牛按照v排序,排完顺序之后,会发现有坐标比当前的x小的,会有坐标比当前的x大的

假设坐标比x小的有num个

那么

距离之和 = x*num - 前面坐标的和 + 后面坐标的和 - (n-num-1)* x

又因为

后面坐标的和 = 整个区间坐标的和 - 前面坐标的和

所以用两个数组,一个数组用来算个数,另外一个数组用来算和

学习的这一篇题解--http://www.acmtime.com/?p=403

#include<iostream>
#include<cstdio>
#include<cstring>
#include <cmath>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;

typedef long long LL;
const int INF = (1<<30)-1;
const int mod=1000000007;
const int maxn=20005;

LL a[maxn];//这个是用来求比x小的个数的
LL b[maxn];//这个是用来求前面的和
LL c[maxn];
int n;

struct node{
int x,v;
}q[maxn];

int cmp(node n1,node n2){
return n1.v < n2.v;
}

int lowbit(int x){ return x & (-x);}

LL sum(LL c[],int x){
LL ret=0;
while( x >0){
ret += c[x]; x-=lowbit(x);
}
return ret;
}

void add( LL c[],int x,int d){
while(x < maxn){
c[x]+=d;x+=lowbit(x);
}
}

int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&q[i].v,&q[i].x);
sort(q+1,q+n+1,cmp);

memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
LL cnt =0;
for(int i=1;i<=n;i++){
int x = sum(a,q[i].x); //统计坐标比x小的有多少个
LL alltotal = sum(b,maxn);//统计这个区间所有坐标的和
LL total = sum(b,q[i].x);//统计前面坐标比x小的的和
cnt += q[i].v * (x * q[i].x - total + alltotal - total - ( i - x -1) * q[i].x);
add(a,q[i].x,1);
add(b,q[i].x,q[i].x);
}
printf("%I64d\n",cnt);
return 0;
}


View Code

加油-------------

goooooooooooooo-------- -------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: