hdu 1025 Constructing Roads In JGShining's Kingdom--最长上升子串(时间优化)

/*
	本题也是最长上升子序列
	同以往不一样的是,需要在时间上做优化
	以往是开一数组,假设为f[i]表示到i能修多少路
	到计算f[q]时,需要遍历q之前的,找到a[i]<a[q](a[]存数据)且f[]最大的,然后加1,就是f[q],这样太浪费时间
	一种优化是把f[]相同的合并
	于是,像本题,用dp[i]存长度为i的最小的数据,如本题存修i条路时,号码最小的富裕城市
	到计算dp[q]时,给root[q](存和q有修路意向的富裕城市)找一个合适的
	地方(不比root[q]小,比他小的会与他交叉,若它前面的数在dp[m],则他即将放在dp[n+1],表明修第m+1条路时,它的号码最小)
	若这地方原来就有上数据,即low(root[q]的位置是由low找出来的,low是root[q]的下标)<=len,直接覆盖,算是更新数据;
	若low>len,把root[q]放到dp[low]后,还要让len更新到当前low,当然,low最多比len大1.
*/
#include<stdio.h>
int num=1;
int root[500100],dp[500100];
void sol(int n)
{
	int low,up,mid,i,len;
	len=1;
	dp[1]=root[1];
	for(i=2;i<=n;i++)
	{
		low=1;
		up=len;
		while(low<=up)
		{
			mid=(low+up)>>1;
			if(dp[mid]>=root[i])
				up=mid-1;
			else low=mid+1;
		}
		dp[low]=root[i];
		if(low>len)
			len++;
	}
	printf("Case %d:\n",num++);
	printf("My king, at most %d road",len);
	if(len>1)
		printf("s");
	printf(" can be built.\n\n");
}
int main()
{
	int n,i,no;
	while(scanf("%d",&n)!=-1)
	{
		for(i=1;i<=n;i++)
		{
			scanf("%d",&no);
			scanf("%d",&root[no]);
		}
		sol(n);
	}
	return 0;
}

你可能感兴趣的:(hdu 1025 Constructing Roads In JGShining's Kingdom--最长上升子串(时间优化))