您的位置:首页 > 运维架构

zoj 2319 Beautiful People 【最长上升序列】

2017-04-19 10:49 323 查看
题意:   给你n个人,每个人有两种权值。然后排队,让你找到最长的队伍人数及分别是哪些人(任意输出一组)。

排队方法为,每个位置的人的两个权值都完全大于前一个人的两个权值。

题解:  最长上升子序列。

两个模板,n^2  and  nlogn

显然 n^2 直接结果就是对的,但是超时。(听说用线段树维护能降低到nlogn。)

nlogn      直接结果不对,但是不超时。

而我当时却没写出来。

首先有nlogn的两种解法,

1. 优先权值x 排序,跑一边, 再优先权值y跑一边,比较最大值,输出,   这样相当于2*n*logn;  (orz  这确实是个好做法)

2. 直接优先x 排序,dp【i】记录的是该点排序后的下标,最后逆着跑出来。就是最优解。

下面第二种解法ac代码:

#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100110;
int T,n;
struct node{
int x,y,nu;
}a[maxn],d[maxn];
int cmp(node aa,node bb){
if(aa.x==bb.x) return aa.y>bb.y;
return aa.x<bb.x;
}
int pre[maxn];
int q[maxn];
int dp[maxn];
int main(){

scanf("%d",&T);
while(T--){
memset(pre,0,sizeof(pre));
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d %d",&a[i].x,&a[i].y);
a[i].nu=i;
}
sort(a+1,a+n+1,cmp);
int len=0;
dp[++len]=1;
for(int i=2;i<=n;++i){
if(a[dp[len]].y<a[i].y) dp[++len]=i,pre[i]=dp[len-1];
else{
int l=1,r=len;
while(l<=r){
int mid=(l+r)/2;
if(a[dp[mid]].y>=a[i].y) r=mid-1;
else l=mid+1;
}
dp[l]=i;
pre[i]=dp[l-1];
}
}
int st=0,t=dp[len];
printf("%d\n",len);
for(int i=len,j=dp[len];i>=1;j=pre[j],--i) q[++st]=a[j].nu;
for(int i=1;i<st;++i) printf("%d ",q[i]);
printf("%d\n",q[st]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: