Codeforces 1311F Moving Points(树状数组 + 离散化 + 思维)

7 篇文章 0 订阅
3 篇文章 0 订阅

题目链接:https://codeforces.ml/contest/1311/problem/F

题意:在一维数轴上有n个点,每个点有一个速度,问这n个点在行驶过程中形成的最小的距离的和。

思路:啊啊啊啊啊啊!!读错题啦,卡了一天。这一题时间可以是小数!!!就是说,任意两个点,要么会在某一时刻相遇,要么永远也不会相遇,所以答案就是那些永远也不会相遇的点的起始位置差的绝对值的和。那怎么判断两个点会不会相遇呢?考虑初中物理公式,x = x i + v i {x}_{i} + {v}_{i} xi+vi * t。任取两个点,联立方程组可得 t = x 2 − x 1 v 1 − v 2 t = \frac{x2 - x1}{v1 - v2} t=v1v2x2x1要想t大于0,有两种情况
1、(x2 > x1 && v1 < v2);
2、(x2 < x1 && v1 > v2);
还有一种情况就是v1 == v2这时候他们永远不可能相遇,所以也算答案的一部分。
所以我们就可以考虑按照速度由小到大对结构体进行排序,之后每次扫到一个i,我们只需要统计前面有多少个数比a[i]小及其总和就好啦,这样我们可以维护两个树状数组,但是这一题数据范围有1e8,所以在加一个离散化就好。具体详见代码。

AC代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

const int maxn = 2e5 + 7;

struct node {
    LL x,y;
}a[maxn];
LL b[maxn];

bool cmp(node aa,node bb) {
    if(aa.y == bb.y) return aa.x < bb.x;
    else return aa.y < bb.y;
}

int n;
LL c1[maxn],c2[maxn];

int lowbit(int x) {
    return x & (-x);
}

void update(LL x,LL y,LL c[]) {
    for(int i = x ; i <= n ; i += lowbit(i)) {
        c[i] += y;
    }
}

LL query(LL x,LL c[]) {
    LL ans = 0;
    for(int i = x ; i > 0 ; i -= lowbit(i)) {
        ans += c[i];
    }
    return ans;
}

int main() {
    while(~scanf("%d",&n)) {
        for(int i = 1 ; i <= n ; i++) {
            scanf("%lld",&a[i].x);
            b[i] = a[i].x;
        }
        for(int i = 1 ; i <= n ; i++) {
            scanf("%lld",&a[i].y);
        }
        sort(b+1,b+n+1);
        int pos = unique(b+1,b+n+1) - (b+1);
        for(int i = 1 ; i <= n ; i++) {
            a[i].x = lower_bound(b+1,b+pos+1,a[i].x) - b;
        }
        sort(a+1,a+n+1,cmp);
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        LL ans = 0;
        for(int i = 1 ; i <= n ; i++) {
            LL res1 = query(a[i].x,c1);///统计大小
            LL res2 = query(a[i].x,c2);///统计个数
            ans += res2 * b[a[i].x] - res1;///更新答案
            update(a[i].x,b[a[i].x],c1);
            update(a[i].x,1,c2);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值