这道题可以用分治的方法解决。(lbgxld说是线段树,但是我觉得分治快而且好写...)
暴力枚举是$O(n^2)$,想要优化,就不能一对一对枚举,最好能用一只奶牛一次计算一群其他的贡献。
这就需要用到听力$v$和坐标大小$x$的关系,可以把它转化为一个二维偏序问题。
首先把听力$v$从大到小排序,控制一维。
然后用归并排序,按$x$从小到大排序。
因为左边一半$(l-mid)$奶牛的$v$一定大于右边的$(mid+1-r)$,那么我们只计算左边的每一个对右边的贡献。
首先枚举统计出右边奶牛坐标的和。
对于左边的一个奶牛,设它的听力为$vi$,坐标为$xi$。
两边已经按$x$从小到大排好,容易统计出有几只奶牛的坐标比它小,而剩余的比它大。
要求坐标差的绝对值,那么分别计算($xi$-小)+(大-$xi$),最后乘这个左边的奶牛的$vi$(因为这个$vi$一定大于所有右边的)。
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq #include<algorithm> #define int long long using namespace std; const int maxn = 1e6; int n,ans; struct vx { int v,x; bool operator < (const vx & N) const { return v>N.v || ( v==N.v && x<N.x); } } a[maxn],b[maxn]; void cdq(int l,int r) { if(l==r)return; int mid = (l+r)>>1; cdq(l,mid); cdq(mid+1,r); int s1 = 0,s2 = 0; for(int i = mid+1;i <= r;i++) s2 += a[i].x; int i = l,j = mid+1,k = l; while(i <= mid) { while(j <= r && a[i].x > a[j].x) { s1 += a[j].x; s2 -= a[j].x; b[k++] = a[j++]; } ans += a[i].v*((j-mid-1)*a[i].x - s1 + s2 - (r-j+1)*a[i].x); b[k++] = a[i++]; } while(j <= r) b[k++] = a[j++]; for(int i = l; i <= r; i++) a[i] = b[i]; } main() { scanf("%lld",&n); for(int i = 1; i <= n; i++) scanf("%lld%lld",&a[i].v,&a[i].x); sort(a+1,a+n+1); cdq(1,n); printf("%lld\n",ans); }