P2782 友好城市 LIS / NLOGN
解题思路
-
问题分析:
-
我们需要选择尽可能多的友好城市对,使得它们的航线不相交。
-
航线不相交的条件是:如果北岸城市A在北岸城市B的左边,那么A对应的南岸城市也必须在南岸城市B的左边。
-
-
关键观察:
-
将北岸城市按坐标排序后,南岸对应的城市坐标必须是一个严格递增的序列,才能保证航线不相交。
-
因此,问题转化为:对南岸城市坐标求最长上升子序列(LIS)。
-
-
算法选择:
-
使用O(nlogn)的LIS算法,因为数据规模较大(N≤2×10^5)。
-
代码注释
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 10, inf = 0x3f3f3f3f; // 定义城市结构体,存储南北岸坐标 struct node { int x, y; // x:北岸坐标,y:南岸坐标 }; node a[N]; // 存储所有城市对 int n; // 城市数量 int f[N]; // f数组用于维护LIS int top; // 当前LIS长度 // 比较函数:按北岸坐标升序排序 bool cmp(node a, node b) { return a.x < b.x; } // 二分查找函数:找到第一个大于等于x的位置 int find(int x) { int l = 1, r = top, res = -1; while (l <= r) { int mid = (l + r) >> 1; if (x <= f[mid]) { // 找到更小的候选值 res = mid; r = mid - 1; } else { l = mid + 1; } } return res; } int main() { cin >> n; // 输入所有城市对 for (int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y; // 按北岸坐标升序排序 sort(a + 1, a + 1 + n, cmp); // 初始化f数组为极大值 memset(f, inf, sizeof(f)); // 计算LIS for (int i = 1; i <= n; i++) { int pos = find(a[i].y); // 找到插入位置 if (pos == -1) { // 如果当前值比所有都大,扩展LIS f[++top] = a[i].y; } else { // 否则替换第一个大于等于它的值 f[pos] = a[i].y; } } // 输出最长不下降子序列长度 cout << top; return 0; }

浙公网安备 33010602011771号