题目地址:http://acdream.info/problem?
pid=1216
这题一開始用的是线段树。后来发现查询的时候还须要DP处理。挺麻烦。。也就不了了之了。。后来想到,这题事实上就是一个二维的最长上升子序列。
。
要先排序,先按左边的数为第一keyword进行升序排序。再按右边的数为第二keyword进行降序排序。这种话,第一keyword同样的的肯定不在一个同一个上升子序列中。然后仅仅对第二keyword进行复杂度为O(n*logn)的DP,找出最长上升序列,然后处理前驱,并输出就可以。
代码例如以下:
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include <set> #include <algorithm> using namespace std; #define LL long long struct node { int x, y, num; }fei[110000]; int cmp(node x, node y) { if(x.x==y.x) return x.y>y.y; return x.x<y.x; } int a[110000], d[110000], pre[110000], len, b[110000]; int bin_seach(int x) { int low=0, high=len, mid, ans; while(low<=high) { mid=low+high>>1; if(a[mid]>=x) { high=mid-1; ans=mid; } else { low=mid+1; } } return ans; } int main() { int n, i, j, pos, cnt; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) { scanf("%d%d",&fei[i].x,&fei[i].y); fei[i].num=i+1; } sort(fei,fei+n,cmp); len=1; a[1]=fei[0].y; d[0]=-1; d[1]=0; memset(pre,-1,sizeof(pre)); for(i=1;i<n;i++) { if(fei[i].y>a[len]) { a[++len]=fei[i].y; pre[i]=d[len-1]; d[len]=i; } else { pos=bin_seach(fei[i].y); a[pos]=fei[i].y; pre[i]=d[pos-1]; d[pos]=i; } } printf("%d ",len); cnt=0; /*for(i=0;i<n;i++) { printf("%d ",fei[i].num); } puts("");*/ for(i=d[len];i!=-1;i=pre[i]) { b[cnt++]=fei[i].num; //printf("%d ",i); } for(i=0;i<cnt-1;i++) printf("%d ",b[i]); printf("%d ",b[cnt-1]); } return 0; }