Codeforces 1311F

题目大意:

坐标轴上有 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;
}
原文地址:https://www.cnblogs.com/stelayuri/p/12463842.html