题目描述
有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航道不相交的情况下,被批准的申请尽量多。
输入格式
第1行,一个整数N,表示城市数。
第2行到第n+1行,每行两个整数,中间用一个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。
输出格式
仅一行,输出一个整数,表示政府所能批准的最多申请数。
输入输出样例
输入
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
输出
4
说明/提示
50% 1<=N<=5000,0<=xi<=10000
100% 1<=N<=2e5,0<=xi<=1e6
思考
保证两条友好城市之间连线不相交,必须要满足所选南岸的友好城市坐标是递增的,这不就是最长上升子序列吗,对于北岸我们需要排序,然后逐个选取北岸对应的南岸友好城市坐标即可
但是呢这道题数据又变大了,N达到了2e5,所以我们需要使用最长上升子序列模型二(acwing课)
一个贪心的思想,每次只需要找到比a[i]小的最大的位置就可以了,避免无用的计算
因为当前位置的前面就是满足最长上升子序列的最大位置,这里用到了二分找最大值
时间复杂度降了,所以可以过
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
typedef pair<int, int> PII;
PII a[N];
int q[N];
int n;
int main(){
scanf("%d", &n);
for(int i = 0; i < n ;i ++ ) scanf("%d%d", &a[i].first, &a[i].second);
sort(a, a + n);
int len = 0; //小于a[i]的最大位置
q[0] = -2e9;
for(int i = 0; i < n; i++){
int l = 0, r = len;
while(l < r){
int mid = l + r + 1 >> 1;
if(q[mid] < a[i].second) l = mid;
else r = mid - 1;
}
len = max(len, r + 1);
q[r + 1] = a[i].second;
}
printf("%d\n", len);
return 0;
}