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

Posted lasomisolaso~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #624 F. Moving Points 离散化 + 树状数组相关的知识,希望对你有一定的参考价值。

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

题意:

思路:

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

结论

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

树状数组

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


以上是关于Codeforces Round #624 F. Moving Points 离散化 + 树状数组的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #624 (Div. 3)

Codeforces Round #624 (Div. 3) B. WeirdSort(排序)

Codeforces Round #624 (Div. 3) D. Three Integers

Codeforces Round #624 (Div. 3) D 题

Codeforces Round #392 (Div. 2) F. Geometrical Progression

Codeforces Round #486 (Div. 3) F. Rain and Umbrellas