BZOJ 2225: [Spoj 2371]Another Longest Increasing (CDQ分治+dp)
阿新 • • 發佈:2018-11-27
題面
Description
給定N個數對(xi, yi),求最長上升子序列的長度。上升序列定義為{(xi, yi)}滿足對i<j有xi<xj且yi<yj。
Input
Output
Sample Input
8
1 3
3 2
1 1
4 5
6 3
9 9
8 7
7 6
Sample Output
3
HINT
資料範圍100000
解題思路
CDQ分治。其實跟模板題的思路差不多,就是用樹狀陣列維護\(dp\)最大值。注意一下更新的順序,就是要從左邊往右邊更新,所以應該先向左分治,再處理,再向右分治。
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int MAXN = 100005; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,dp[MAXN],f[MAXN],cpy[MAXN],u,ans; struct Data{ int id,x,y; friend bool operator<(const Data A,const Data B){ return A.x<B.x; } }data[MAXN],tmp[MAXN]; inline void add(int x,int k){ for(;x<=u;x+=x&-x) f[x]=max(f[x],k); } inline int query(int x){ int ret=0; for(;x;x-=x&-x) ret=max(ret,f[x]); return ret; } inline void clear(int x){ for(;x<=u;x+=x&-x) f[x]=-1; } inline bool cmp(Data A,Data B){ return A.id<B.id; } void cdq(int l,int r){ if(l==r) return ;int mid=(l+r)>>1;cdq(l,mid); int L=l,R=mid+1,o=l; sort(data+mid+1,data+r+1); while(L<=mid && R<=r){ if(data[L].x<data[R].x) add(data[L].y,dp[data[L].id]),L++; else dp[data[R].id]=max(dp[data[R].id],query(data[R].y-1)+1),R++; } while(R<=r) {dp[data[R].id]=max(dp[data[R].id],query(data[R].y-1)+1);R++;} for(int i=l;i<=mid;i++) clear(data[i].y);sort(data+mid+1,data+r+1,cmp); cdq(mid+1,r);L=l;R=mid+1; while(L<=mid && R<=r) { if(data[L].x<data[R].x) tmp[o++]=data[L++]; else tmp[o++]=data[R++]; } while(L<=mid) tmp[o++]=data[L++]; while(R<=r) tmp[o++]=data[R++]; for(int i=l;i<=r;i++) data[i]=tmp[i]; } int main(){ memset(f,-1,sizeof(f));n=rd(); for(int i=1;i<=n;i++) data[i].x=rd(),data[i].y=cpy[i]=rd(),data[i].id=i,dp[i]=1; sort(cpy+1,cpy+1+n);u=unique(cpy+1,cpy+1+n)-cpy-1; for(int i=1;i<=n;i++) data[i].y=lower_bound(cpy+1,cpy+1+u,data[i].y)-cpy;cdq(1,n); for(int i=1;i<=n;i++) ans=max(ans,dp[i]); printf("%d\n",ans); return 0; }