【Codeforces Round #624】 F. Moving Points 离散化 + 树状数组

n o n i n t e g e r non-integer 看成非负整数了。。。想了半天样例三是咋回事,看了洛谷的翻译才反应过来。。。

题意:

在这里插入图片描述

思路:

对于每个点,我们只需要将它与它左边的点的距离累加起来就是最后答案。

结论

首先考虑一个点的速度为正的情况,考虑它与它左边的点的距离。
如果左边的点的速度为负,那么距离为两点的坐标差。
如果左边的点的速度为正且速度小于等于这个点的速度, 那么距离为两点的坐标差。
如果左边的点的速度为正且速度大于这个点的速度,那么距离为0 。因为时间可以小数,所以肯定有一个时刻左边的点会追上这个点。
总结就是如果左边的点速度大于这个点的速度,距离为0;否则距离为两点的坐标差。
然后考虑一个点的速度为负的情况,如上分析,也可以得出同样的结论。

树状数组

我们可以以速度为区间,建立树状数组。首先将这些点以 x x 坐标从小到大排序。然后一个一个插入到树状数组中,这样就可以保证在某个点插入之前,树状数组中的点全部都是这个点左边的点。速度大于这个点的点我们不用考虑, 只考虑小于这个点速度的点。
接下来一个问题就是距离怎么求,我们可以利用树状数组简单地求出速度小于这个点速度的点的 x x 坐标之和。其实距离的累加和就是 n u m x s u m num * x - sum ,
n u m num 是左边距离不是 0 0 的点的个数, s u m sum 是小于这个点速度的点的 x x 坐标和。这样问题就可以解决了。
树状数组维护一个序列:速度为x的点的坐标和,速度为x的点的个数。
详细见代码。
注意坐标和会爆 i n t int .

代码:

/**
* Author : Xiuchen
* Date : 2020-03-25-18.48.40
* Description : F.cpp
*/
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 2e5 + 100;
int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}
int n, lsh[maxn], lshnum;
ll c[2][maxn];
struct node{
    ll x, v;
} a[maxn];
bool cmp(node a, node b){
    return a.x < b.x;
}
void add(int x, int d, int k){
    while(x <= lshnum){
        c[k][x] += d;
        x += x & (-x);
    }
}
ll ask(int x, int k){
    ll res = 0;
    while(x){
        res += c[k][x];
        x -= x & (-x);
    }
    return res;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i].x);
    for(int i = 1; i <= n; i++){
        scanf("%lld", &a[i].v);
        lsh[i] = a[i].v;
    }
    sort(lsh + 1, lsh + 1 + n);
    lshnum = unique(lsh + 1, lsh + 1 + n) - lsh - 1;
    sort(a + 1, a + 1 + n, cmp);
    for(int i = 1; i <= n; i++) a[i].v = lower_bound(lsh + 1, lsh + 1 + lshnum, a[i].v) - lsh;
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        ll num = ask(a[i].v, 0);
        ll sum = ask(a[i].v, 1);
        ans += num * a[i].x - sum;
        add(a[i].v, 1, 0);
        add(a[i].v, a[i].x, 1);
    }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44607936/article/details/105104077