Constructing Roads In JGShining's Kingdom
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7192 Accepted Submission(s): 2103
Problem Description
JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in two parallel lines.
Half of these cities are rich in resource (we call them rich cities) while the others are short of resource (we call them poor cities). Each poor city is short of exactly one kind of resource and also each rich city is rich in exactly one kind of resource. You may assume no two poor cities are short of one same kind of resource and no two rich cities are rich in one same kind of resource.
With the development of industry, poor cities wanna import resource from rich ones. The roads existed are so small that they're unable to ensure the heavy trucks, so new roads should be built. The poor cities strongly BS each other, so are the rich ones. Poor cities don't wanna build a road with other poor ones, and rich ones also can't abide sharing an end of road with other rich ones. Because of economic benefit, any rich city will be willing to export resource to any poor one.
Rich citis marked from 1 to n are located in Line I and poor ones marked from 1 to n are located in Line II.
The location of Rich City 1 is on the left of all other cities, Rich City 2 is on the left of all other cities excluding Rich City 1, Rich City 3 is on the right of Rich City 1 and Rich City 2 but on the left of all other cities ... And so as the poor ones.
But as you know, two crossed roads may cause a lot of traffic accident so JGShining has established a law to forbid constructing crossed roads.
For example, the roads in Figure I are forbidden.
In order to build as many roads as possible, the young and handsome king of the kingdom - JGShining needs your help, please help him. ^_^
Input
Each test case will begin with a line containing an integer n(1 ≤ n ≤ 500,000). Then n lines follow. Each line contains two integers p and r which represents that Poor City p needs to import resources from Rich City r. Process to the end of file.
Output
For each test case, output the result in the form of sample.
You should tell JGShining what's the maximal number of road(s) can be built.
Sample Input
Sample Output
Case 1: My king, at most 1 road can be built. Case 2: My king, at most 2 roads can be built.
Hint
Huge input, scanf is recommended.
Author
JGShining(极光炫影)
解题报告:就是求最长上升子序列,一开始用的普通办法求的!直接TEL;就在网上找了一个时间复杂度为O(nlogn)的算法,其算法思想为:(网上找的)
假设要寻找最长上升子序列的序列是a[n],然后寻找到的递增子序列放入到数组b中。
(1)当遍历到数组a的第一个元素的时候,就将这个元素放入到b数组中,以后遍历到的元素都和已经放入到b数组中的元素进行比较;
(2)如果比b数组中的每个元素都大,则将该元素插入到b数组的最后一个元素,并且b数组的长度要加1;
(3)如果比b数组中最后一个元素小,就要运用二分法进行查找,查找出第一个比该元素大的最小的元素,然后将其替换。
在这个过程中,只重复执行这两步就可以了,最后b数组的长度就是最长的上升子序列长度。例如:如该数列为:
5 9 4 1 3 7 6 7
那么:
5 //加入
5 9 //加入
4 9 //用4代替了5
1 9 //用1代替4
1 3 //用3代替9
1 3 7 //加入
1 3 6 //用6代替7
1 3 6 7 //加入
最后b中元素的个数就是最长递增子序列的大小,即4。
要注意的是最后数组里的元素并不就一定是所求的序列,
例如如果输入 2 5 1
那么最后得到的数组应该是 1 5
而实际上要求的序列是 2 5
代码如下:
#include<stdio.h>
const int MAXN=500010;
int a[MAXN],b[MAXN];
//用二分查找的方法找到一个位置,使得num>b[i-1] 并且num<b[i],并用num代替b[i]
int Search(int num,int low,int high)
{
int mid;
while(low<=high)
{
mid=(low+high)/2;
if(num>=b[mid]) low=mid+1;
else high=mid-1;
}
return low;
}
int DP(int n)
{
int i,len,pos;
b[1]=a[1];
len=1;
for(i=2;i<=n;i++)
{
if(a[i]>=b[len])//如果a[i]比b[]数组中最大还大直接插入到后面即可
{
len=len+1;
b[len]=a[i];
}
else//用二分的方法在b[]数组中找出第一个比a[i]大的位置并且让a[i]替代这个位置
{
pos=Search(a[i],1,len);
b[pos]=a[i];
}
}
return len;
}
int main()
{
int n;
int iCase=0;
int i,j;
int x,y;
while(scanf("%d",&n)!=EOF)
{
iCase++;
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
a[x]=y;
}
int res=DP(n);
printf("Case %d:\n",iCase);
if(res==1)
{
printf("My king, at most 1 road can be built.\n\n");
}
else
printf("My king, at most %d roads can be built.\n\n",res);
}
return 0;
}