传送门:https://vjudge.net/problem/POJ-1990
题意:m头牛,每头牛有两个值v和x。然后每两头牛之间的值是abs(x1-x2) * Max(v1,v2)。问所有m*(m-1)/2对牛之间值的总和。
白书上来的。就是用树状数组做。首先肯定是按照v排序,这样就可以不用管v了。接下来我们看看x。
我们先对所有牛的x排序,然后每头牛有一个idx代表这头牛的x在所有牛的x中排第几位。然后有两个树状数组,num[N]和dis[N]。num[i]表示比i小的有多少个,dis[i]表示比i小的x的和(这里的i指在X[N]数组排名第i位)。然后我按照v从小到大的顺序枚举每一头牛,每次进行维护,这样枚举到的牛所查询树状数组里的都是v比它小的。这样这头牛对答案的贡献就是由两部分构成。
第一部分x比它小的 就是比v×(x-xi)的和,整理就是v×(cnt×x-dis[i]),
然后我在记录目前为止总共加了多少个点进树状数组,以及这些点的x的总和totdis。
这样第二部分就是x比它大的就很好求了。
讲的可能不是很清楚,具体看代码吧。
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 const int N=2e4+9; 15 int n; 16 ll num[N<<2],dis[N<<2],X[N]; 17 void add(int x){ 18 ll val=X[x]; 19 for(;x<=n;x+=x&-x) dis[x]+=val,++num[x]; 20 } 21 ll qnum(int x){ 22 ll ans=0; 23 for(;x>0;x-=x&-x) ans+=num[x]; 24 return ans; 25 } 26 ll qdis(int x){ 27 ll ans=0; 28 for(;x>0;x-=x&-x) ans+=dis[x]; 29 return ans; 30 } 31 struct cow{ 32 ll v,x; 33 int idx; 34 bool operator<(const cow& b) const{ 35 return v<b.v; 36 } 37 }a[N]; 38 int main() { 39 scanf("%d",&n); 40 for(int i=1;i<=n;++i){ 41 scanf("%lld%lld",&a[i].v,&a[i].x); 42 X[i]=a[i].x; 43 } 44 sort(X+1,X+1+n); 45 sort(a+1,a+1+n); 46 for(int i=1;i<=n;++i){ 47 a[i].idx=lower_bound(X+1,X+1+n,a[i].x)-X; 48 } 49 ll totcnt=0,totdis=0; 50 ll res=0; 51 for(int i=1;i<=n;++i){ 52 ll lcnt=qnum(a[i].idx); 53 ll ldis=qdis(a[i].idx); 54 res+=a[i].v*(lcnt*a[i].x-ldis); 55 res+=a[i].v*((totdis-ldis)-(totcnt-lcnt)*a[i].x); 56 ++totcnt; 57 totdis+=a[i].x; 58 add(a[i].idx); 59 } 60 printf("%lld",res); 61 return 0; 62 }
来源:https://www.cnblogs.com/xiaobuxie/p/10859430.html