题目大意:
坐标轴上有 n 个点,每个点有初始位置 x 与速度 v
问在运动过程中,点两两之间最小距离之和
2<=n<=200000 1<=x<=1e8 -1e8<=v<=1e8
解题思路:
两两点情况共三种:
1、左边的点速度小于右边的点:这种情况距离会随运动时间增加而增加,最小距离即初始距离
2、左边的点速度等于右边的点:这种情况距离不变,最小距离即初始距离
3、左边的点速度大于右边的点:这种情况距离会随运动时间增加而先减小后增加,最小距离为0,不需要考虑
所以可以按照 x 从小到大循环每个点,对答案的贡献为与左边每个速度小于等于自己的点的距离差之和
对于点的距离差之和,可以由 当前点的x * 左边点的个数 - 左边点的x之和得到
所以很容易想到用两个树状数组,一个维护个数,一个维护x之和
则树状数组的下标可以使用 v
但是因为v的范围为±1e8,点的个数只有2e5,所以先对 v 进行离散化
然后在循环时,先执行答案增加,再对树进行维护
(280ms/2000ms)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; int n,tree[200050];//tree维护个数 ll tree2[200050];//tree2维护x之和 int lowbit(int x){ return x&(-x); } void add(int in1){ while(in1<=n){ tree[in1]++; in1+=lowbit(in1); } } int sum(int in){ int r=0; while(in>0){ r+=tree[in]; in-=lowbit(in); } return r; } void add2(int in1,ll in2){ while(in1<=n){ tree2[in1]+=in2; in1+=lowbit(in1); } } ll sum2(ll in){ ll r=0; while(in>0){ r+=tree2[in]; in-=lowbit(in); } return r; } struct node{ int x,v; bool operator < (const node& a) const{ return x<a.x; }//按x升序排序 }ar[200050]; int y[200050]; void solve(){ cin>>n; int i; for(i=1;i<=n;i++) cin>>ar[i].x; for(i=1;i<=n;i++){ cin>>ar[i].v; y[i]=ar[i].v; } sort(y+1,y+1+n); for(i=1;i<=n;i++) ar[i].v=lower_bound(y+1,y+1+n,ar[i].v)-y;//离散化 sort(ar+1,ar+1+n); ll ans=0; for(i=1;i<=n;i++){ ans+=1LL*sum(ar[i].v)*ar[i].x-sum2(ar[i].v); add(ar[i].v); add2(ar[i].v,ar[i].x); } cout<<ans<<' '; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); solve(); return 0; }