F - Moving Points树状数组
题:https://codeforces.com/contest/1311/problem/F
题意:给定x轴上的点以及他们的速度v,只在x轴上运动,求最小的dis之和,注意,这里的时间是可随意的,比如对于其中一个点 i 来说,只要其他点运动到离自己距离最小即可,而不是同步运动
分析:对于一对点 i 和 j 来说,以点 i 为基准,要是xj<xi,那么只要vj>xi就可以让dis为0,要是xj>xi,,那么只要vj<vi就可以让dis为0,其他情况就俩者不动就能保持dis最小为abs(xi-xj);
总结一下,只要xi<=xj&&vi<=vj,那么对答案的贡献就是abs(xi-xj),(因为越移动dis越大)其他的贡献就为0;
所以我们只要讲x升序,就可避免重复算点对,对于一个点 i 而言,对答案的贡献就是:比xi小的点的数目*xi - 比xi小的点的x之和;
因为统计全程与v的具体值无关只有大小,所可以进行离散化处理;
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int M=5e5+4; const int N=2e5+5; ll tr[M][3]; struct node{ ll x,v; bool operator <(const node &b)const{ return x<b.x; } }a[M]; ll lisan[M]; void update(int x,ll c){ while(x<=N){ tr[x][0]++; tr[x][1]+=c; x+=x&(-x); } } ll query(int x,int k){ ll ans=0; while(x){ ans+=tr[x][k]; x-=(x&(-x)); } return ans; } int main(){ ios::sync_with_stdio(false); cin.tie(0); int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i].x; for(int i=1;i<=n;i++) cin>>a[i].v,lisan[i]=a[i].v; sort(a+1,a+1+n); sort(lisan+1,lisan+1+n); int m=unique(lisan+1,lisan+1+n)-lisan-1; ll ans=0; for(int i=1;i<=n;i++){ int pos=lower_bound(lisan+1,lisan+1+m,a[i].v)-lisan; ll num=query(pos,0); ll sum=query(pos,1); ans+=a[i].x*num-sum; update(pos,a[i].x); } cout<<ans<<endl; return 0; }