forest114514
2024-09-15 11:42:11
众所周知,二分队列能做形如
那么我们要做的决策单调性 DP 形如
假设我们计算完了
具体地,首先用
注意到花费了
这个东西好像就是什么 Wilber 算法?不过 Wilber 算法是线性的,这个只能说是不加 SWAMK 优化的 Wilber 算法。
效率测试方面,在诗人小 G 这道题中这个方法和二分队列时间差别不是很大,在一些点慢
Wilber 的写法:
void divide(int l,int r,int L,int R){
if(l>r) return;
int mid=l+r>>1,lim=min(mid-1,R);
F[mid]=(NODE){G[L].val+calc(L,mid),L};
rep(i,L+1,lim){
LD tmp=G[i].val+calc(i,mid);
if(tmp<F[mid].val) F[mid]=(NODE){tmp,i};
}
divide(l,mid-1,L,F[mid].ch),divide(mid+1,r,F[mid].ch,R);
}
void Wilber(){
int r=0,c=0;
while(r<n){
int ri=min(n,r+(r-c+1));
F=g,G=f,divide(r+1,ri,c,r);
F=h,G=g,divide(r+2,ri,r+1,ri);
int t=r+2;
while(t<=ri&&g[t].val-eps<h[t].val) ++t;
rep(i,r+1,t-1) f[i]=g[i];
if(t>ri) r=ri;
else f[t]=h[t],c=r+1,r=t;
}
}
二分队列:
head=tail=1;
q[1].c=0,q[1].l=1,q[1].r=n;
for(int i=1;i<=n;++i){
while(head<tail&&q[head].r<i)head++;
q[head].l=i;
int c=q[head].c;
ch[i]=c;f[i]=f[c]+calc(c,i);//1
while(head<tail&&cost(i,q[tail].l)<=cost(q[tail].c,q[tail].l))tail--;
int ll=q[tail].l, rr=q[tail].r+1;
while(ll<rr){
int mid=(ll+rr)>>1;
if(cost(i,mid)<=cost(q[tail].c,mid))rr=mid;
else ll=mid+1;
}
if(ll<=n) q[tail].r=ll-1,q[++tail].c=i,q[tail].l=ll,q[tail].r=n;
}
总结一下毕竟要做两遍决策单调性分治,所以常数非常大,一般情况下还是写二分队列好了,而且在
不过比如 CF868F 和 P5574 就能把因子