【SPOJ2371】LIS2
题目大意:求二维最长上升子序列的长度。
题解:
可以看出,这个问题等价于三维偏序问题。
不过在进行分治的时候要注意,由于 dp 转移是有顺序的,因此只能先处理左半部分,再处理左半部分对右边的贡献,最后处理右半部分。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,ans,d[maxn],tot,dp[maxn];
struct node{int x,y,id;}p[maxn],tmp[maxn];
int bit[maxn];
void modify(int pos,int val){
for(int i=pos;i<=tot;i+=i&-i)bit[i]=max(bit[i],val);
}
int query(int pos){
int ret=0;
for(int i=pos;i;i-=i&-i)ret=max(ret,bit[i]);
return ret;
}
void clear(int pos){
for(int i=pos;i<=tot;i+=i&-i)bit[i]=0;
}
void cdq(int l,int r){
if(l==r)return;
int mid=l+r>>1;
cdq(l,mid);
sort(p+l,p+mid+1,[](const node &a,const node &b){return a.x<b.x;});
sort(p+mid+1,p+r+1,[](const node &a,const node &b){return a.x<b.x;});
for(int x=l,y=mid+1;y<=r;y++){
while(x<=mid&&p[x].x<p[y].x)modify(p[x].y,dp[p[x].id]),++x;
dp[p[y].id]=max(dp[p[y].id],query(p[y].y-1)+1);
}
for(int i=l;i<=mid;i++)clear(p[i].y);
sort(p+mid+1,p+r+1,[](const node &a,const node &b){return a.id<b.id;});
cdq(mid+1,r);
}
void read_and_parse(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&p[i].x,&p[i].y);
p[i].id=i,d[++tot]=p[i].y;
}
sort(d+1,d+tot+1);
tot=unique(d+1,d+tot+1)-d-1;
for(int i=1;i<=n;i++)p[i].y=lower_bound(d+1,d+tot+1,p[i].y)-d;
}
void solve(){
for(int i=1;i<=n;i++)dp[i]=1;
cdq(1,n);
for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
printf("%d\n",ans);
}
int main(){
read_and_parse();
solve();
return 0;
}