JZOJ4829. 独木桥

题目大意

给定一个无限长的的实数轴。给定 n 个互不相同数轴上整数点,表示每个动点的起始位置。每个动点有一个运动方向(向左或向右),以每秒1单位的速度运动。两个动点相遇后,会同时改变运动方向。现有q个询问,每个询问要求编号为 k 的点在经过t秒后的位置。

Data Constraint
n,q2105,t109

题解

首先注意两个结论:

  1. 两个点相遇后改变方向可以视为交换点的编号,而点的方向不变按原方向继续运动。
  2. 每个点在数轴上的相对位置是一定不变的。

然后,考虑将运动方向不同的点分成两组。
对于询问编号为 k 的点的位置,我们只需要找到在当前这个时间下与k相对排名相同的数即可。例如:在初始的时候 k 是从左往右数第x个点,现在询问 k ,就是要在当前的所有位置中找第x小的位置。
这个可以二分套二分解决。

时间复杂度: O(nlog2)

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;

#define N 200000 + 10
typedef long long ll ;
struct Note {
    int v , h ;
    Note ( int V = 0 , int H = 0 ) { v = V , h = H ; }
} tp[N] ;

int p[N] , d[N] , Rank[N] ;
ll a[N] , b[N] ;
int n , Q , k , t ;
ll ans ;

bool cmp( Note a , Note b ) { return a.v < b.v ; }

bool Check( ll st ) {
    int wz = 0 ;
    int l = 1 , r = a[0] ;
    while ( l <= r ) {
        int mid = (l + r) / 2 ;
        if ( (ll)a[mid] - t <= st ) l = mid + 1 , wz = mid ;
        else r = mid - 1 ;
    }
    if ( wz >= k ) return 1 ;
    if ( b[k-wz] + t <= st && b[0] >= k - wz ) return 1 ;
    return 0 ;
}

int main() {
    freopen( "bridge.in" , "r" , stdin ) ;
    freopen( "bridge.out" , "w" , stdout ) ;
    scanf( "%d" , &n ) ;
    for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &p[i] ) , tp[i] = Note( p[i] , i ) ;
    for (int i = 1 ; i <= n ; i ++ ) {
        scanf( "%d" , &d[i] ) ;
        if ( d[i] ) b[++b[0]] = p[i] ;
        else a[++a[0]] = p[i] ;
    }
    sort( tp + 1 , tp + n + 1 , cmp ) ;
    for (int i = 1 ; i <= n ; i ++ ) Rank[tp[i].h] = i ;
    sort( a + 1 , a + a[0] + 1 ) ;
    sort( b + 1 , b + b[0] + 1 ) ;
    scanf( "%d" , &Q ) ;
    for (int i = 1 ; i <= Q ; i ++ ) {
        scanf( "%d%d" , &k , &t ) ;
        k = Rank[k+1] ;
        ll l = -1e9-5000 , r = 2e9+5000 ;
        while ( l <= r ) {
            ll mid = (l + r) / 2 ;
            if ( Check(mid) ) r = mid - 1 , ans = mid ;
            else l = mid + 1 ;
        }
        printf( "%lld\n" , ans ) ;
    }
    return 0 ;
}

以上.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值