poj 1990 MooFest
题意:
若干头牛排列在一条坐标轴上(位置都不同),每头牛都有一个音量vi,任意两头牛i,j之间要交流,他们发出的音量就是max(vi,vj) * 它们的距离。
问n / (n-1)对牛交流的音量的总和。
思路:
先无脑n ^ 2了一波,果然tle了,是我太naive。
首先把牛按照音量递增排序,对于当前的牛,只需要知道数组中在它前面的牛到它的距离的绝对值之和,那么就很好办了。
关键就是求前面的牛到它的距离的绝对值之和。
用两个树状数组,一个维护数量的前缀,一个维护位置和的前缀。
用一个dis来累加当前的距离的总和。
对于当前的牛,数量树状数组可以求出小于它的位置的牛的个数cnt,位置和树状数组可以求出小于等于它的牛的位置之和sum。
那么它前面的小于它的位置的牛到它的距离之和就是cnt * x[i] - sum,
大于它的位置的牛到它的距离之和就是dis - sum - (i - cnt) * x[i]。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N = 2e5 + 10; 6 int c[N]; 7 long long d[N]; 8 struct node 9 { 10 int v,p; 11 } a[N]; 12 int mx; 13 int lowbit(int x) 14 { 15 return x&(-x); 16 } 17 void addx(int x) 18 { 19 for (int i = x;i <= 20000;i += lowbit(i)) c[i]++; 20 } 21 int getx(int x) 22 { 23 int ans = 0; 24 for (int i = x;i > 0;i -= lowbit(i)) ans += c[i]; 25 return ans; 26 } 27 void addd(int x,int y) 28 { 29 for (int i = x;i <= 20000;i += lowbit(i)) d[i] += y; 30 } 31 long long getd(int x) 32 { 33 long long ans = 0; 34 for (int i = x;i > 0;i -= lowbit(i)) ans += d[i]; 35 return ans; 36 } 37 bool cmp(node aa,node bb) 38 { 39 if (aa.v == bb.v) return aa.p < bb.p; 40 return aa.v < bb.v; 41 } 42 int main() 43 { 44 int n; 45 while (scanf("%d",&n) != EOF) 46 { 47 memset(c,0,sizeof(c)); 48 memset(d,0,sizeof(d)); 49 long long ans = 0; 50 for (int i = 0;i < n;i++) scanf("%d%d",&a[i].v,&a[i].p); 51 sort(a,a+n,cmp); 52 long long dis = 0; 53 for (int i = 0;i < n;i++) 54 { 55 int cnt = getx(a[i].p); 56 long long tmp = 0; 57 long long tmpd = getd(a[i].p); 58 tmp += 1LL * cnt * a[i].p - tmpd; 59 tmp += dis - tmpd - 1LL * (i - cnt) * a[i].p; 60 ans += tmp * a[i].v; 61 addx(a[i].p); 62 addd(a[i].p,a[i].p); 63 dis += a[i].p; 64 } 65 printf("%lld\n",ans); 66 } 67 return 0; 68 }
康复训练中~欢迎交流!