cdq分治,dp(i)表示以i为结尾的最长LIS,那么dp的递推是依赖于左边的。
因此在分治的时候需要利用左边的子问题来递推右边。
(345ms? 区间树TLE
/********************************************************* * ------------------ * * author AbyssFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> using namespace std; const int MAX_N = 100000+5; int dp[MAX_N]; int x[MAX_N], y[MAX_N]; int ys[MAX_N]; int id[MAX_N]; int N; int ns; int *cur; bool cmp(int a,int b) { return cur[a] < cur[b] || (cur[a] == cur[b] && a > b);//这是为了保证严格的单调性 } int compress(int *r, int *dat, int *a, int n) { for(int i = 0; i < n; i++){ r[i] = i; } cur = dat; sort(r,r+n,cmp); a[r[0]] = 1; for(int i = 1; i < n; i++){ int k = r[i], p = r[i-1]; a[k] = dat[k] == dat[p]?a[p]:a[p]+1; } return a[r[n-1]]; } int C[MAX_N]; void add(int yi,int d) { while(yi <= ns){ C[yi] = max(C[yi],d); yi += yi&-yi; } } int mx_pfx(int yi) { int re = 0; while(yi > 0){ re = max(C[yi],re); yi &= yi-1; } return re; } void clr(int yi) { while(yi <= ns){ C[yi] = 0; yi += yi&-yi; } } void dv(int l, int r) { if(r-l <= 1){ dp[l]++; } else { int md = (l+r)>>1; dv(l,md); for(int i = l; i < r; i++) id[i] = i; sort(id+l,id+r,cmp); //x维度 for(int i = l; i < r; i++){ int k = id[i]; if(k < md){ //position 维度 add(ys[k],dp[k]); //BIT下标是 y维度 } else { //查询位置前保证了BIT里的元素, 位置md之前,x严格小于待查元素 dp[k] = max(dp[k], mx_pfx(ys[k]-1));//y严格小于待查元素的最大dp值 } } for(int i = l; i < r; i++){ if(id[i] < md) clr(ys[id[i]]); } dv(md,r); } } void solve() { scanf("%d",&N); for(int i = 0; i < N; i++){ scanf("%d%d",x+i,y+i); } ns = compress(id,y,ys,N); cur = x; dv(0,N); printf("%d\n",*max_element(dp,dp+N)); } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif solve(); return 0; }
时间: 2024-12-29 23:40:03