[SGU 199] Beautiful People
[SGU 199] Beautiful People
The most prestigious sports club in one city has exactly N members. Each of its members is strong and beautiful. More precisely, i-th member of this club (members being numbered by the time they entered the club) has strength S i and beauty B i . Since this is a very prestigious club, its members are very rich and therefore extraordinary people, so they often extremely hate each other. Strictly speaking, i-th member of the club Mr X hates j-th member of the club Mr Y if S i ≤ S j and B i≥ B j or if S i ≥ S j and B i ≤ B j (if both properties of Mr X are greater then corresponding properties of Mr Y, he doesn't even notice him, on the other hand, if both of his properties are less, he respects Mr Y very much).
To celebrate a new 2003 year, the administration of the club is planning to organize a party. However they are afraid that if two people who hate each other would simultaneouly attend the party, after a drink or two they would start a fight. So no two people who hate each other should be invited. On the other hand, to keep the club presti≥ at the apropriate level, administration wants to invite as many people as possible.
Being the only one among administration who is not afraid of touching a computer, you are to write a program which would find out whom to invite to the party.
Input
The first line of the input file contains integer N — the number of members of the club. ( 2 ≤ N ≤ 100,000 ). Next N lines contain two numbers each — S i and B irespectively ( 1 ≤ S i, B i ≤ 10 9 ).
Output
On the first line of the output file print the maximum number of the people that can be invited to the party. On the second line output N integers — numbers of members to be invited in arbitrary order. If several solutions exist, output any one.
Sample test(s)
Input
4
1 1
1 2
2 1
2 2
Output
2
1 4
作为经典比赛中的一道题,想必这一定是重点的重点,那就写博记录一下.
题解:
本题虽有两个奇怪的不等式,事实上就是求最长上升子序列(读者可以想想为什么)
于是,先对两个序列排序,排序规则是第二关键字从大到小,第一关键字从小到大
然后我们就有了一个正常做lis的序列
但是因为要nlogn内完成,所以还需要二分或者树状数组优化,那么我这里只讲二分的方法,另一种留给读者去思考
首先你必须得会二分求lis,不然学习一下这个http://blog.csdn.net/wall_f/article/details/8295812
那么接下来就方便了,你只需要此时二分出第二关键字比a[i]小的最大的答案,如果他比最大的还大,那么把它加到二分序列中
同时记录下这一位是由哪一个数推过来的,即是最后所要的答案
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 int n,ans=0,pre[100010],s[100010]; 6 struct xint{int x,y,num;}a[100010]; 7 bool cmp(xint x,xint y){return x.x==y.x?x.y<y.y:x.x<y.x;} 8 int main(){ 9 scanf("%d",&n); 10 for (int i=1;i<=n;++i) scanf("%d%d",&a[i].x,&a[i].y),a[i].num=i; 11 sort(a+1,a+n+1,cmp); 12 for (int i=1;i<=n;++i){ 13 int l=0,r=ans; 14 while (l<r){ 15 int mid=l+(r-l+1)/2; 16 if (a[s[mid]].y>=a[i].y) r=mid-1; else l=mid; 17 } 18 int res=l+1; pre[i]=s[res-1]; 19 if (a[i].y<a[s[res]].y||s[res]==0) s[res]=i; 20 ans=max(ans,res); 21 } 22 printf("%d\n",ans); 23 for (int i=s[ans];i;i=pre[i]) printf("%d ",a[i].num); 24 }