题意翻译
Farmer John 的 NN 头奶牛 ( 1 ≤ N ≤ 10^5 ) 正在一条长度无限的跑道上慢跑,每头奶牛都有一个不同的开始位置,以及不同的跑步速度。
为了方便奶牛们互相超越,整个跑道被分成了若干条赛道。在同一时刻,不可能有在同一条赛道上的两头奶牛占据相同的位置。
现在奶牛们要跑 T 分钟,在跑步过程中,他们不会改变自己所在的赛道和自己跑步的速度。FJ想要知道,为了奶牛间不会发生冲突,他需要至少准备多少条赛道。
输入格式:第一行包括两个整数 N 和 T 。接下来 N 行,每行两个整数 p_i 和 v_i( p_i , v_i ≤ 10^9 ),分别代表奶牛的初始位置和速度。
输出格式:一个整数,代表最少需要的跑道数目。
题目描述
Farmer John's NN cows (1 <= N <= 100,000) are out exercising their hooves again, jogging along an infinite track. Each cow starts at a distinct position on the track, and some cows run at different speeds.
The track is divided into lanes so that cows may move past each other. No two cows in the same lane may ever occupy the same position. Farmer John doesn't want any cow to have to change lanes or adjust speed, and he wonders how many lanes he will need to accomplish this if the cows are going to run for TT minutes (1 <= T <= 1,000,000,000).
输入输出格式
输入格式:
The first line of input contains N and T
The following N lines each contain the initial position and speed of a single cow. Position is a nonnegative integer and speed is a positive integer; both numbers are at most 1 billion. All cows start at distinct positions, and these will be given in increasing order in the input.
输出格式:
A single integer indicating the minimum number of lanes necessary so that no two cows in the same lane ever occupy the same location (including at time T).
输入输出样例
输入样例#1:
5 3
0 1
1 2
2 3
3 2
6 1
输出样例#1:
3
因为题目给出了起点速度和时间,我们就可以求出每一头奶牛所走的区间
假如有两个区间A和B 交叉在了一起
具体来说就是 A.st< B.st 而且 B.ed < A.ed
因为每当速度快的奶牛追上速度慢的奶牛后会超过他,所以最终点就一定大于慢的奶牛到达的最终点
所以交叉在一起的区间肯定要分开路走
由此得知,我们要求的是最多层次的完全覆盖区间
就比如说这个图
因为这个图最多的完全覆盖的有四层,所以需要备四条跑道,情景描述大概是这样的
奶牛1会超过234,多准备一条道
奶牛2会超过34,多准备一条道
奶牛3会超过4,多准备一条道
奶牛4要一条跑道
一共就是四条
我们先将st排序,将ed变成点权,那不就变成了求最长的不上升子序列
维护这个,首先要离散化不然肯定直接爆炸,离散以后最多2n,如果用O(N^2)的做法肯定会超时
所以就要用O(nlogn)的做法,这是废话
一开始不知道怎么做,后来看了一下别人的博客
先设当前要搜索的节点为i(离散完后又n个不同的值)
那么现在要做的就是找到比i的权值大并且长度最大的那个点
并且更新节点i的值(树状数组维护)
代码
#include <iostream>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int N = 1e5 + 10 ;
struct node {
LL dic , spd , dstn1 , dstn ;
//dic,dstn1表示 头和尾 ,spd表示速度,dstn表示离散后尾的值
int f ; //f表示以当前点结尾的最长不上升子序列
} a[N] ; int tree[N<<1] , n ; //tree为树状数组
inline bool cmp_dic( const node &x , const node &y ) {
return x.dic < y.dic ;
}
inline bool cmp_dstn1( const node &x , const node &y ) {
return x.dstn1 < y.dstn1 ;
}
inline int lowbit( int x ) { return x & ( -x ) ; }
void update( int x , int val ) {
for ( int i = x ; i >= 1 ; i -= lowbit(i) ) //更新向小的
tree[i] = max( tree[i] , val ) ;
}
int query( int x ) {
int ans = 0 ;
for ( int i = x ; i <= n + 1 ; i += lowbit(i) ) //因为是找比他大的最大f值,所以从小到大,n+1是为了保险
ans = max ( ans , tree[i] ) ;
return ans ;
}
int main() {
LL t ; cin >> n >> t ; //一下为输入和离散化
for ( int i = 1 ; i <= n ; i ++ ) {
cin >> a[i].dic >> a[i].spd ;
a[i].dstn1 = a[i].dic + t * a[i].spd ;
}
sort ( a+1 , a+n+1 , cmp_dstn1 ) ; a[0].dstn1 = a[1].dstn -1 ;
int tot = 0 ;
for ( int i = 1 ; i <= n ; i ++ ) {
if ( a[i].dstn1 != a[i-1].dstn1 ) tot ++ ;
a[i].dstn = tot ;
}
sort ( a+1 , a+n+1 , cmp_dic ) ; int ans = 0 ; //求最长 不下降子序列
for ( int i = 1 ; i <= n ; i ++ ) {
a[i].f = query( a[i].dstn ) + 1 ;
update ( a[i].dstn , a[i].f ) ;
ans = max ( ans , a[i].f ) ;
}
cout << ans << endl ;
return 0 ;
}
我用了cin读入,会很慢(不过比较好看),建议大家改为read(快读)