Description
Solution
设
f[i]
表示前i个点已经被解决了,并且第i个点选,最小代价。
那么可以考虑转移
f[i]=min(f[j]+c[i]),j<i,p[j]<p[i]
且
∀k,j<k<i,p[k]<p[j]或p[k]>p[i]
即对于所有能转移到i的j,它们之间的点要么与i相交,要么与j相交。
正确性显然。
那么将其投影到二维平面上,一个点就是
(i,p[i])
那么对于每一对能转移的j,i那么一定是j为左下角,i为右上角构成的矩形中,没有其他的点。
自行感受一下。
那么很显然,这样的j构成了一个p[j]递减,且其中所有 p[j]<p[i] 的单调栈。
于是考虑数据结构维护这个单调栈。
由于此时p[j]在值域,不方便维护,不妨将横纵坐标对调。
即一个点投影在 (p[i],i) 上。
那么按照i的顺序从左到右插入
对于当前点只需要查询 x=p[i] 直线左边的j递减的单调栈
设
G(l,r,h)
表示
[l,r]
内,
y=h
这条直线上方的所有点构成的
j
递减的单调栈的
如果l=r,直接查询。
如果
[l,r]
不是线段树上的完整区间,那就继续向下递归。
如果
[l,r]
是线段树上的完整区间,mid为区间中点。
设 rmax 表示右子区间 [mid+1,r] 的纵坐标最大值。
既然其是一个纵坐标递减的单调栈,那么左子区间
[l,mid]
的
h
限制提到了
当然,如果
rmax<h
,那么右子区间就会全部被弹掉,直接返回
G(l,mid,h)
否则返回
min(G(l,mid,rmax),G(mid+1,r,h))
直接递归复杂度是 O(N2logN) 的,还没有直接DP快。
然而可以发现,对于一个线段树上完整的区间 [l,r] ,查询 G(l,r,h) ,若 rmax>h ,显然rmax是当前点下一定的,这样完全可以预处理。
在插入新点的时候更新有关区间的答案,rmax可以在跑右子区间的时候计算。
分析复杂度。
对于一个查询,一个区间包含了
log
个完整的线段树区间,每个完整的区间都会向下走
log
层到底,因此一次查询复杂度
log2
对于插入,一个位置被 log 个区间的左子区间包含,需要重新计算这些区间的 G(l,mid,rmax)
计算是可以先算底层的,在通过底层的优化计算上面的,每次计算的复杂度相当于查询完整区间的复杂度也是 log
相当于平摊了插入和复杂度
总复杂度
O(Nlog2N)
Code
因为是口胡,所以没有程序!(懒得打了。。)