通过这个题SPOJ LIS2学习了下CDQ分治,巧妙之处在于区间拆半,用左区间来更新右区间。
题目就是求最长的二维LIS,也就是三维偏序。
把每对值
(x,y)
的下标作为第一维,
x
作为第二维,
void CDQ(int L,int R)
{
if(L == R) return;
int m = (L+R) >> 1;
CDQ(L,m);
solve(L,R);
CDQ(m + 1,R);
}
相当于一个二叉树上的中序处理,在solve(L,R)时,就是分为区间 [L,mid] , [mid+1,R] ,然后对两个区间都根据y作为关键字排序,这个时候每个区间内的第一维可能会被打乱,但是总体来说,右区间的x关键字还是大于左区间的,所以接下来就是利用区间 [L,mid] 去更新 [mid+1,R] ,部分代码如下:
int j = L;
//update[m+1,R] by [L,m] for x is sorted
for(int i = m+1;i <= R;i ++){
while(j<=m && a[j].y<a[i].y){
update(a[j].z,dp[a[j].x]);
j++;
}
int id = a[i].x;
dp[id] = max(dp[id],read(a[i].z-1) + 1);
}
解释下,update就是单点更新,每次更新完后,再去查询所有小于 a[i].z 的值里边最大的一个,去更新 dp[id] 。
如果你还有地方没看懂的话,点 CDQ分治