2021上海市赛-H-二分答案

题目大意:

一维坐标上有 n n n个车.每个车有坐标,速度(有方向),类型.问你最早在多少秒有车发生碰撞
n ≤ 1 e 5 n \leq 1e5 n1e5

题目思路:

显然二分答案。关键在于如何check相撞?

没有相撞等价于任意两对不同类型的车之间的相对位置没有发生变化.

这么check显然是对的,但是显然复杂度是爆炸的.

但我们只需要存一个车左边离他最近的不同类的车的下标以及右边离它最近的不同类的车的下标。

二分后sort,然后 O ( n ) O(n) O(n)的check每个车是否符合条件即可。

因为一旦发生相撞,一定有车的左右状态发生改变.
或者说:相对位置没发生改变等价于每个车左右最近的两个不同类的车没发生改变

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct Node
{
    ll p , v , t , id;
    bool operator < (const Node & a){
        return p < a.p;
    }
}a[maxn] , b[maxn] , c[maxn];
int L[maxn] , R[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n , k; cin >> n >> k;
    for (int i = 1 ; i <= n ; i++){
        cin >> a[i].p >> a[i].v >> a[i].t;
        a[i].id = i;
    }
    sort(a + 1 , a + 1 + n);
    R[a[n].id] = -1;
    for (int i = n - 1 ; i >= 1 ; i--){
        if (a[i].t == a[i + 1].t){
            R[a[i].id] = R[a[i + 1].id];
        }else {
            R[a[i].id] = a[i + 1].id;
        }
    }
    L[a[1].id] = -1;
    for (int i = 2 ; i <= n ; i++){
        if (a[i].t == a[i - 1].t){
            L[a[i].id] = L[a[i - 1].id];
        }else {
            L[a[i].id] = a[i - 1].id;
        }
    }
    ll l = 1 , r = 3e9;
  //  ll l = 1 , r = 1;
    while (l <= r){
        ll mid = l + r >> 1;
        for (int i = 1 ; i <= n ; i++){
            b[i] = a[i];
            b[i].p += mid * b[i].v;
        }
        sort(b + 1 , b + 1 + n);
        for (int i = 1 ; i <= n ; i++) c[b[i].id] = b[i];
        bool ok = true;
        for (int i = 1 ; i <= n ; i++){
            int pos = b[i].id;
            if (L[pos] != -1){
                if (c[L[pos]].p >= c[pos].p){
                    ok = false;
                    break;
                }
            }
            if (R[pos] != -1){
                if (c[R[pos]].p <= c[pos].p){
                    ok = false;
                    break;
                }
            }
        }
        if (ok) l = mid + 1;
        else r = mid - 1;
    }
    if (r == 3e9) cout << -1 << endl;
    else cout << r << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值