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;
}


 

你可能感兴趣的:(树状数组)