友好城市
传送门:https://www.luogu.org/problemnew/show/P2782
想像两条纵向的数轴,从上到下的数依次是从小到大的,然后左右数轴连着一些线段,两条线段不相交当且仅当一条线段的左右端点均小于(或大于)另一条线段的左右端点。因此问题转化成对线段的左端点从小到大排序后,对右端点求最长上升子序列。但是若按常规的方法求最长上升子序列会超时,因此我们用upper_bound,省去了不必要的枚举。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e5+1;
inline int read()
{
static char ch;
while((ch = getchar()) < '0' || ch > '9');
int ret = ch - 48;
while((ch = getchar()) >= '0' && ch <= '9')
ret = ret * 10 + ch - 48;
return ret;
}
int n,f[N],ans,p;
struct node
{
int x,y;
}t[N];
bool cmp(node a,node b)
{
return a.x < b.x;
}
int main()
{
n = read();
for(int i = 1;i <= n;i++)
{
t[i].x = read();
t[i].y = read();
f[i] = 1;
}
sort(t+1,t+n+1,cmp);
/*for(int i = 1;i <= n;i++) printf("%d ",t[i].y);
printf("\n");*/
f[++ans] = t[1].y;
for(int i = 2;i <= n;i++)
{
int p = upper_bound(f + 1,f + ans + 1,t[i].y) - f;//返回t[i].y后第一个大于它的元素位置
f[p] = t[i].y;
if(p > ans) ans++;
/*for(int i = 1;i <= n;i++) printf("%d ",f[i]);
printf("\n");*/
}
printf("%d",ans);
return 0;
}