首页 > 代码库 > hdu1025 Constructing Roads In JGShining's Kingdom (nlogn的LIS)

hdu1025 Constructing Roads In JGShining's Kingdom (nlogn的LIS)

题目链接


第一次写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;
}