Codeforces Round #624 (Div. 3) F 离散化+树状数组

Codeforces Round #624 (Div. 3) F

题目

在这里插入图片描述
在这里插入图片描述

题目大意

给出 n 个点和他们的初始位置 x 和移动速度 v,问所有点对在任意时刻全部最小值的和是多少,不是同一时刻而是每个点对的最小值的和,可以是任意时刻。

解题思路

思考一下易得,其实就是若i,j两个点,存在 x i < x j 且 v i ≤ v j x_i\lt x_j 且 v_i \le v_j xi<xjvivj,则两个这两个点对答案的贡献就是abs( x i − x j x_i - x_j xixj),因为只需要速度的相对大小关系,所以我们可以进行离散化方便处理,离散化代码如下

sort(lsh, lsh+n);
    for(int i = 0; i < n; i++)
    {
        a[i].second = lower_bound(lsh, lsh+n, a[i].second) - lsh + 1;
    }

这样,a[i].second就记录了速度的大小关系,然后对整个数组按照坐标从小到大排序,那么这个时候依次依速度为小标插入树状数组并统计,注意:这个时候坐标已经按照小到大的顺序,那么我们每次依速度为小标插入一个数据的时候,就记录比现在这个点小的速度在树状数组有多少个就行了,这样就能保证这些点对满足 x i < x j 且 v i ≤ v j x_i\lt x_j 且 v_i \le v_j xi<xjvivj
为了方便计算,我们要两个树状数组,一个是统计比这个点小的点的个数,一个统计比这个点小的点数之和。

代码

a.first 记录坐标
a.second 记录速度/大小关系
lsh 离散化需要的暂时数组
f1 记录比这个点小的点的个数
f2 比这个点小的点数之和

#include <iostream>
#include <cstdio>
#include <set>
#include <list>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <string>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <fstream>
#include <iomanip>
using namespace std;
#define dbg(x) cerr << #x " = " << x <<endl;
typedef pair<int, int> P;
typedef long long ll;
inline int lowbit(int x)
{
    return x & -x;
}
const int MAXN = 2e5+5;
ll f1[MAXN << 2], f2[MAXN << 2];
P a[MAXN];
int lsh[MAXN];
int n;
ll sum(int x, ll *arr)
{
    ll ret = 0;
    while(x > 0)
    {
        ret += arr[x];
        x -= lowbit(x);
    }
    return ret;
}
void add(int x, ll d, ll *arr)
{
    while(x <= n)
    {
        arr[x] += d;
        x += lowbit(x);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        cin >> a[i].first;
    }
    for(int i = 0; i < n; i++)
    {
        cin >> a[i].second;
        lsh[i] = a[i].second;
    }
    sort(lsh, lsh+n);
    for(int i = 0; i < n; i++)
    {
        a[i].second = lower_bound(lsh, lsh+n, a[i].second) - lsh + 1;
    }
    sort(a, a+n);
    ll ans = 0;
    for(int i = 0; i < n; i++)
    {
        ll tmp1 = sum(a[i].second, f1);
        ll tmp2 = sum(a[i].second, f2);
        ans += tmp1 * a[i].first - tmp2;
        add(a[i].second, 1, f1);
        add(a[i].second, a[i].first, f2);
    }
    cout << ans << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值