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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/starve/p/12363851.html