【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;
}
posted @ 2019-06-30 16:04  shellpicker  阅读(184)  评论(0编辑  收藏  举报