ybtAu「动态规划」第6章 动态 DP
这是 neatisaac 的金牌导航题解!
A. 【例题1】最大子段和
DDP 板子。
令 \(f_i\) 表示以 \(i\) 结尾的最大子段和,\(g_i\) 表示前 \(i\) 个数的最大子段和,有:
\[\large f_i=\max(f_{i-1}+a_i,a_i)
\\\large g_i=\max(g_{i-1},f_i)
\]
放进矩阵,有:
\[\large
\left[
\begin{array}{l}
f_i\\g_i\\0
\end{array}
\right]
=\left[
\begin{array}{l}
a_i&-\infin&a_i\\
a_i&0&a_i\\
-\infin&-\infin&0
\end{array}
\right]
\left[
\begin{array}{l}
f_{i-1}\\g_{i-1}\\0
\end{array}
\right]
\]
线段树维护即可。
#include <iostream>
#include <cstring>
#define int long long
#define N 500005
int n,m,a[N],rt;
struct Mat
{
int o[3][3];
Mat() {memset(o,-0x3f,sizeof o);}
Mat(int x)
{
o[0][0]=o[0][2]=o[1][0]=o[1][2]=x;
o[1][1]=o[2][2]=0;
o[0][1]=o[2][0]=o[2][1]=-1e18;
}
Mat operator *(const Mat &g) const
{
Mat ret;
for(int k=0;k<3;k++) for(int i=0;i<3;i++) for(int j=0;j<3;j++)
ret.o[i][j]=std::max(ret.o[i][j],o[i][k]+g.o[k][j]);
return ret;
}
};
namespace SGT
{
Mat d[N<<1];
int ls[N<<1],rs[N<<1],idx;
#define mid (lb+rb>>1)
int build(int lb,int rb)
{
int x=++idx;
if(lb==rb) return d[x]=a[lb],x;
ls[x]=build(lb,mid),rs[x]=build(mid+1,rb),d[x]=d[ls[x]]*d[rs[x]];
return x;
}
void md(int x,int t,int k,int lb,int rb)
{
if(lb==rb) d[x]=k;
else ((t<=mid)?md(ls[x],t,k,lb,mid):md(rs[x],t,k,mid+1,rb)),d[x]=d[ls[x]]*d[rs[x]];
}
Mat qr(int x,int l,int r,int lb,int rb)
{
if(l<=lb&&rb<=r) return d[x];
if(r<=mid) return qr(ls[x],l,r,lb,mid);
if(l>mid) return qr(rs[x],l,r,mid+1,rb);
return qr(ls[x],l,r,lb,mid)*qr(rs[x],l,r,mid+1,rb);
}
#undef mid
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
for(int i=1;i<=n;i++) std::cin>>a[i];
rt=SGT::build(1,n);
for(int i=1,op,x,y;i<=m;i++)
{
std::cin>>op>>x>>y;
if(op==1)
{
if(x>y) std::swap(x,y);
Mat ans=SGT::qr(rt,x,y,1,n);
std::cout<<std::max(ans.o[1][0],ans.o[1][2])<<'\n';
}
if(op==2) SGT::md(rt,x,y,1,n);
}
}
B. 【例题2】最大独立集
树上 DDP 板子,也是 DDP 更主要的应用。
但是懒得打式子了。
#include <iostream>
#include <cstring>
#define N 200005
int n,m,a[N],hed[N],tal[N],nxt[N],cnte,f[N][2],g[N][2],rt,li[N],bot[N];
void adde(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
struct Mat
{
int o[2][2];
Mat() {memset(o,-0x3f,sizeof o);}
Mat operator *(const Mat &g) const
{
Mat ret;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
ret.o[i][j]=std::max(ret.o[i][j],o[i][k]+g.o[k][j]);
return ret;
}
} b[N];
namespace SGT
{
Mat d[N<<1];
int ls[N<<1],rs[N<<1],idx;
#define mid (lb+rb>>1)
int build(int lb,int rb)
{
int x=++idx;
if(lb==rb) return d[x]=b[li[lb]],x;
return ls[x]=build(lb,mid),rs[x]=build(mid+1,rb),d[x]=d[ls[x]]*d[rs[x]],x;
}
void md(int x,int t,int lb,int rb)
{
if(lb==rb) d[x]=b[li[lb]];
else (t<=mid)?md(ls[x],t,lb,mid):md(rs[x],t,mid+1,rb),d[x]=d[ls[x]]*d[rs[x]];
}
Mat qr(int x,int l,int r,int lb,int rb)
{
if(l<=lb&&rb<=r) return d[x];
if(r<=mid) return qr(ls[x],l,r,lb,mid);
if(l>mid) return qr(rs[x],l,r,mid+1,rb);
return qr(ls[x],l,r,lb,mid)*qr(rs[x],l,r,mid+1,rb);
}
#undef mid
};
namespace HLD
{
int dep[N],fa[N],son[N],dfn[N],top[N],siz[N],idx;
void dfs1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
dep[tal[i]]=dep[x]+1,fa[tal[i]]=x,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void dfs2(int x,int tp)
{
li[dfn[x]=++idx]=x,top[x]=tp,bot[tp]=std::max(bot[tp],idx);
f[x][0]=0,f[x][1]=a[x],b[x].o[0][0]=0,b[x].o[1][0]=a[x];
if(son[x]) dfs2(son[x],tp),f[x][0]+=std::max(f[son[x]][0],f[son[x]][1]),f[x][1]+=f[son[x]][0];
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]])
{
dfs2(tal[i],tal[i]),f[x][0]+=std::max(f[tal[i]][0],f[tal[i]][1]),f[x][1]+=f[tal[i]][0];
b[x].o[0][0]+=std::max(f[tal[i]][0],f[tal[i]][1]),b[x].o[1][0]+=f[tal[i]][0];
}
b[x].o[0][1]=b[x].o[0][0];
}
void md(int x,int k)
{
b[x].o[1][0]+=k-a[x];
a[x]=k;
Mat la,nw;
while(x)
{
la=SGT::qr(rt,dfn[top[x]],bot[top[x]],1,n);
SGT::md(rt,dfn[x],1,n);
nw=SGT::qr(rt,dfn[top[x]],bot[top[x]],1,n);
x=fa[top[x]];
b[x].o[0][0]+=std::max(nw.o[0][0],nw.o[1][0])-std::max(la.o[0][0],la.o[1][0]);
b[x].o[1][0]+=nw.o[0][0]-la.o[0][0],b[x].o[0][1]=b[x].o[0][0];
}
}
};
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
memset(f,-0x3f,sizeof f);
std::cin>>n>>m;
for(int i=1;i<=n;i++) std::cin>>a[i];
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,adde(u,v),adde(v,u);
HLD::dfs1(1),HLD::dfs2(1,1),rt=SGT::build(1,n);
for(int i=1,x,y;i<=m;i++)
{
std::cin>>x>>y;
HLD::md(x,y);
Mat tmp=SGT::qr(rt,1,bot[1],1,n);
std::cout<<std::max(tmp.o[0][0],tmp.o[1][0])<<'\n';
}
}
C. 保卫王国
把必须驻扎军队的城市设为 \(-\infin\),不得驻扎军队的城市设为 \(+\infin\)。
#include <iostream>
#include <cstring>
#define int long long
#define N 200005
int n,m,p[N],f[N][2],hed[N],tal[N],nxt[N],cnte,li[N],bot[N],rt,sum;
void adde(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
struct Mat
{
int o[2][2];
Mat() {memset(o,0,sizeof o);}
Mat operator *(const Mat &g) const
{
Mat ret;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) ret.o[i][j]=std::max(ret.o[i][j],o[i][k]+g.o[k][j]);
return ret;
}
} a[N];
namespace SGT
{
Mat d[N<<1];
int ls[N<<1],rs[N<<1],idx;
#define mid (lb+rb>>1)
int build(int lb,int rb)
{
int x=++idx;
if(lb==rb) return d[x]=a[li[lb]],x;
return ls[x]=build(lb,mid),rs[x]=build(mid+1,rb),d[x]=d[ls[x]]*d[rs[x]],x;
}
void md(int x,int t,int lb,int rb)
{
if(lb==rb) d[x]=a[li[lb]];
else (t<=mid)?md(ls[x],t,lb,mid):md(rs[x],t,mid+1,rb),d[x]=d[ls[x]]*d[rs[x]];
}
Mat qr(int x,int l,int r,int lb,int rb)
{
if(l<=lb&&rb<=r) return d[x];
if(r<=mid) return qr(ls[x],l,r,lb,mid);
if(l>mid) return qr(rs[x],l,r,mid+1,rb);
return qr(ls[x],l,r,lb,mid)*qr(rs[x],l,r,mid+1,rb);
}
#undef mid
};
namespace HLD
{
int dfn[N],fa[N],son[N],siz[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1,f[x][1]=p[x];
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
f[x][0]+=std::max(f[tal[i]][0],f[tal[i]][1]);
f[x][1]+=f[tal[i]][0];
}
}
void dfs2(int x,int tp)
{
top[li[dfn[x]=++idx]=x]=tp,bot[tp]=std::max(bot[tp],idx);
a[x].o[1][0]=p[x],a[x].o[1][1]=-1e12;
if(!son[x]) return;
dfs2(son[x],tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]])
{
dfs2(tal[i],tal[i]);
a[x].o[0][0]+=std::max(f[tal[i]][0],f[tal[i]][1]);
a[x].o[1][0]+=f[tal[i]][0];
}
a[x].o[0][1]=a[x].o[0][0];
}
void md(int x,int k)
{
a[x].o[1][0]+=k-p[x],p[x]=k;
Mat la,nw;
while(x)
{
la=SGT::qr(rt,dfn[top[x]],bot[top[x]],1,n);
SGT::md(rt,dfn[x],1,n);
nw=SGT::qr(rt,dfn[top[x]],bot[top[x]],1,n);
x=fa[top[x]];
a[x].o[0][0]+=std::max(nw.o[0][0],nw.o[1][0])-std::max(la.o[0][0],la.o[1][0]);
a[x].o[1][0]+=nw.o[0][0]-la.o[0][0],a[x].o[0][1]=a[x].o[0][0];
}
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::string tmp1;
std::cin>>n>>m>>tmp1;
for(int i=1;i<=n;i++) std::cin>>p[i],sum+=p[i];
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,adde(u,v),adde(v,u);
HLD::dfs1(1),HLD::dfs2(1,1),rt=SGT::build(1,n);
for(int i=1,u,x,v,y;i<=m;i++)
{
std::cin>>u>>x>>v>>y;
if((u==HLD::fa[v]||v==HLD::fa[u])&&!x&&!y) {std::cout<<"-1\n";continue;}
int tu=p[u],tv=p[v];
if(x==0) HLD::md(u,1e12);
if(x==1) HLD::md(u,-1e12);
if(y==0) HLD::md(v,1e12);
if(y==1) HLD::md(v,-1e12);
Mat mt=SGT::qr(rt,1,bot[1],1,n);
int ans=std::max(mt.o[0][0],mt.o[1][0]);
if(x==0) ans=ans-1e12+tu;
if(y==0) ans=ans-1e12+tv;
std::cout<<sum-ans<<'\n';
HLD::md(u,tu),HLD::md(v,tv);
}
}
D. 洪水
令 \(g_i\) 表示所有轻子树的答案,有:
\[\large f_i=\max(w_i,g_i+f_{son_i})
\\\large g_i=\sum g_v(v\neq son_i)
\]
建立矩阵即可。
#include <iostream>
#include <cstring>
#define int long long
#define N 400005
int n,m,w[N],hed[N],tal[N],nxt[N],cnte,rt,li[N],bot[N],f[N];
void adde(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
struct Mat
{
int o[2][2];
Mat() {memset(o,0x3f,sizeof o);}
Mat operator *(const Mat &g) const
{
Mat ret;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
ret.o[i][j]=std::min(ret.o[i][j],o[i][k]+g.o[k][j]);
return ret;
}
} a[N];
namespace SGT
{
Mat d[N<<1];
int ls[N<<1],rs[N<<1],idx;
#define mid (lb+rb>>1)
int build(int lb,int rb)
{
int x=++idx;
if(lb==rb) return d[x]=a[li[lb]],x;
return ls[x]=build(lb,mid),rs[x]=build(mid+1,rb),d[x]=d[ls[x]]*d[rs[x]],x;
}
void md(int x,int t,int lb,int rb)
{
if(lb==rb) d[x]=a[li[lb]];
else (t<=mid)?md(ls[x],t,lb,mid):md(rs[x],t,mid+1,rb),d[x]=d[ls[x]]*d[rs[x]];
}
Mat qr(int x,int l,int r,int lb,int rb)
{
if(l<=lb&&rb<=r) return d[x];
if(r<=mid) return qr(ls[x],l,r,lb,mid);
if(l>mid) return qr(rs[x],l,r,mid+1,rb);
return qr(ls[x],l,r,lb,mid)*qr(rs[x],l,r,mid+1,rb);
}
#undef mid
};
namespace HLD
{
int fa[N],son[N],siz[N],dfn[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1,f[x]=0;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dfs1(tal[i]),siz[x]+=siz[tal[i]],f[x]+=f[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
a[x].o[0][0]=f[x]-f[son[x]],a[x].o[0][1]=w[x];
if(!son[x]) a[x].o[0][0]=1e18;
f[x]=son[x]?std::min(f[x],w[x]):w[x];
a[x].o[1][0]=a[x].o[1][1]=0;
}
void dfs2(int x,int tp)
{
if(!x) return;
top[li[dfn[x]=++idx]=x]=tp,bot[tp]=idx,dfs2(son[x],tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) dfs2(tal[i],tal[i]);
}
void md(int x,int k)
{
a[x].o[0][1]+=k,w[x]+=k;
while(x)
{
Mat la=SGT::qr(rt,dfn[top[x]],bot[top[x]],1,n);
SGT::md(rt,dfn[x],1,n);
Mat nw=SGT::qr(rt,dfn[top[x]],bot[top[x]],1,n);
x=fa[top[x]],a[x].o[0][0]+=std::min(nw.o[0][0],nw.o[0][1])-std::min(la.o[0][0],la.o[0][1]);
}
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n;
for(int i=1;i<=n;i++) std::cin>>w[i];
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,adde(u,v),adde(v,u);
HLD::dfs1(1),HLD::dfs2(1,1),rt=SGT::build(1,n);
std::cin>>m;
for(int i=1,x,y;i<=m;i++)
{
char op;
std::cin>>op>>x;
if(op=='Q')
{
Mat mt=SGT::qr(rt,HLD::dfn[x],bot[HLD::top[x]],1,n);
std::cout<<std::min(mt.o[0][0],mt.o[0][1])<<'\n';
}
if(op=='C') std::cin>>y,HLD::md(x,y);
}
}
E. 切树游戏
未完待续……

浙公网安备 33010602011771号