第一次写nlogn复杂度的LIS,纪念一下。
题目意思是说。有两条平行线,两条平行线都有n个城市,都是从左到右标记为1--n,一条线上是富有城市,一个是贫穷城市。输入n,接下来有n行,p,r表示穷城市p和富有城市r
之间可以建一条路(p的顺序是1--n,一个贫穷城市只对应一个富有城市(弱爆的语文描述能力T_T)),公路不能交叉。
问最多可以建多少条公路。
在别处看到的对nlogn解法的解释吧算是:
时间复杂度:(NlogN):
除了算法一的定义之外,增加一个数组b,b[i]用以表示长度为i最长子序列的最后一个数最小可以是多少。易证:i<j时,b[i]<b[j]。
在二分查找时,一直更新b[]内容,设此时b的总长度为k,
若1. arr[i] >= b[k], 则b[k+1] = arr[i];
若2. arr[i] < b[k], 则在b[1..k]中用二分搜索大于arr[i]的最小值,返回其位置pos,然后更新b[pos]=arr[i]。
code如下(自己手写了一个二分,又用了下STL里面upper_bound,都可以):
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
//#define local
using namespace std;
const int maxn=500010;
int poor[maxn],ro[maxn];
int n;
int Binary_search(int x,int k)
{
int low=1,high=k;
while(low<=high)
{
int mid=(low+high)/2;
if(ro[mid]<=x)
low=mid+1;
else
high=mid-1;
}
return low;
}
int lis()
{
int k=1;
ro[k]=poor[1];
for(int i=2;i<=n;i++)
{
if(poor[i]>=ro[k])
ro[++k]=poor[i];
else
{
//int pos=Binary_search(poor[i],k);
int pos=upper_bound(ro+1,ro+k+1,poor[i])-(ro);
ro[pos]=poor[i];
}
}
return k;
}
int main()
{
#ifdef local
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // local
int cnt=0;
while(~scanf("%d",&n))
{
int x,y;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
poor[x]=y;
}
int ans=lis();
printf("Case %d:\n",++cnt);
if(ans<=1)
printf("My king, at most %d road can be built.\n\n",ans);
else
printf("My king, at most %d roads can be built.\n\n",ans);
}
return 0;
}