题意:给出直线上若干个不同动点的初始位置和速度,求每两个点之间能达到的最短距离之和。
思路:首先我们发现,若x1<x2,并且v1<=v2的话,则两个点之间的距离一定是非递减的,也就是说,这两个之间的最短距离就是他们初始时刻的距离,因此这道题本质上是找到x1<x2并且v1<v2的点对。我们发现其实是一道二维偏序的题。
对于该题,我们考虑将点按照初始横坐标排序,通过树状数组,我们能快速找到速度小于当前点的数量,为了求出距离,我们需要额外开一个数组存储信息。当然,由于速度范围较大,我们需要将速度离散化。
#include<set>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 200005
#define ll long long
int n;
ll c1[maxn],c2[maxn],arr[maxn],p[maxn];
pair<int,int> points[maxn];
void update(int x,int val,ll sum[]){
while(x<=n){
sum[x]+=val;
x+=x&-x;
}
}
ll query(int x,ll sum[]){
ll res=0;
while(x){
res+=sum[x];
x-=x&-x;
}
return res;
}
int main(void){
ll sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&points[i].first);
for(int i=1;i<=n;i++){
scanf("%d",&points[i].second);
arr[i]=points[i].second;
}
sort(points+1,points+n+1);
sort(arr+1,arr+n+1);
unique(arr+1,arr+n+1);
for(int i=1;i<=n;i++)
p[i]=lower_bound(arr+1,arr+n+1,points[i].second)-arr;
for(int i=1;i<=n;i++){
update(p[i],points[i].first,c1);
update(p[i],1,c2);
sum+=query(p[i],c2)*points[i].first-query(p[i],c1);
}
printf("%lld\n",sum);
return 0;
}