POJ 1990 MooFest (树状数组)
题意:由n头牛,不同的听力值v,当i,j想要通话时,需要max(v(i),v(j))*(dist[i]-dist[j])的volume,问这n*(n-1)/2对牛总共的volume时多少。
思路:非常好的一道树状数组,自己想了很长时间没想起来,最后看了结题报告才恍然大悟,对n头牛按v进行排序,由小到大,tre_sumx[i.x]记录前i头牛于x的坐标的总和,tre_cnt[i.x]记录前i头牛坐标低于x的牛的头数,total记录前i头牛的总x和,那么对于每个牛,依靠这三个量就可以计算出i牛和之前的所有牛的volume和。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
using namespace std;
const int BORDER = (1<<20)-1;
const int MAXSIZE = 37;
const int MAXN = 20100;
const int INF = 1000000000;
#define CLR(x,y) memset(x,y,sizeof(x))
#define ADD(x) x=((x+1)&BORDER)
#define IN(x) scanf("%d",&x)
#define OUT(x) printf("%d\n",x)
#define MIN(m,v) (m)<(v)?(m):(v)
#define MAX(m,v) (m)>(v)?(m):(v)
#define ABS(x) ((x)>0?(x):-(x))
typedef struct{
int v;
int x;
}Node;
Node node[MAXN];
__int64 tre_cnt[MAXN];
__int64 tre_sumx[MAXN];
int n,n_tre;
bool cmp(const Node& a,const Node& b)
{
if(a.v == b.v)
return a.x < b.x;
return a.v < b.v;
}
int lowbit(int x)
{
return x&(-x);
}
void modify(__int64* tre,const int& ind,const int& delta)
{
for(int i = ind; i <= n_tre; i += lowbit(i))
tre[i] += delta;
}
__int64 get_sum(__int64* tre, const int& ind)
{
__int64 sum = 0;
for(int i = ind; i > 0; i -= lowbit(i))
sum += tre[i];
return sum;
}
int init()
{
CLR(tre_cnt,0);
CLR(tre_sumx,0);
n_tre = 20005;
return 0;
}
int input()
{
for(int i = 0; i < n; ++i)
{
scanf("%d%d",&node[i].v,&node[i].x);
}
return 0;
}
int work()
{
int i,j,cnt;
__int64 ans,sum,total;
ans = 0;
total = 0;
sort(node,node+n,cmp);
modify(tre_cnt,node[0].x,1);
modify(tre_sumx,node[0].x,node[0].x);
total += node[0].x;
for(i = 1; i < n; ++i)
{
sum = get_sum(tre_sumx,node[i].x);
cnt = get_sum(tre_cnt,node[i].x);
ans += node[i].v*(node[i].x*((cnt<<1)-i)+total-(sum<<1));
modify(tre_cnt,node[i].x,1);
modify(tre_sumx,node[i].x,node[i].x);
total += node[i].x;
}
cout<<ans<<endl;
return 0;
}
int main()
{
while(IN(n)!=EOF)
{
init();
input();
work();
}
return 0;
}