P4719 【模板】动态dp

P4719 【模板】动态dp


神仙东西orz

动态dp简单来说就是dp可以用矩阵来转移,用LCT来维护矩阵的转移。

那么简单来说就是pj难度的DP,tg难度的矩乘,以及noip+难度的LCT。

pj难度dp:设\(dp[i][j]\)表示点i不选/选。\(f[x][0]=\sum f[son][1],f[x][1]=\sum \max(f[son][0],f[son][1])\)

tg难度的矩乘:用新的姿势来定义矩乘,把*换成+,+换成取max。因为依然具有分配率,所以还是可以矩乘的。

noip+难度LCT:LCT要维护子树信息,设\(g[x][0/1]\)表示只看x和的虚子树的答案。

众所周知LCT上每个点都有重儿子。

\(f[x][0]=\max(g[x][0]+f[heavyson][0],g[x][0]+f[heavyson][1])\)

\(f[x][1]=g[x][1]+f[heavyson][0]\)

f可以用一个1*2的矩形\(\left[\begin{matrix}f[x][0] && f[x][1]\\\end{matrix}\right]\)来搞。

配一个矩乘的东西。上面这个很好弄,只要

\[ \left[ \begin{matrix} f[heavyson][0] && f[heavyson][1] \end{matrix} \right] \times \left[ \begin{matrix} g[x][0] && ??\\ g[x][0] && ??\\ \end{matrix} \right] =\left[\begin{matrix}f[x][0] && f[x][1]\\\end{matrix}\right] \]

就好了。下面那个不太好搞,不过可以化成

\(f[x][1]=\max(g[x][1]+f[heavyson][0],-inf)\)

所以乘的矩阵应该是

\[ \left[ \begin{matrix} f[heavyson][0] && f[heavyson][1] \end{matrix} \right] \times \left[ \begin{matrix} g[x][0] && g[x][1]\\ g[x][0] && -inf\\ \end{matrix} \right] =\left[\begin{matrix}f[x][0] && f[x][1]\\\end{matrix}\right] \]

这样就好了。

感觉还有很多东西没讲清,反正我博客也没人看,咕咕咕着吧。顺便推荐一篇

https://www.luogu.org/blog/gkxx-is-here/solution-p4751

(代码是P4751 【动态dp【加强版】】的)

#include<bits/stdc++.h>
#define il inline
#define vd void
#define inf 100000000
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Matrix{
    int s[2][2];
    Matrix(){s[0][0]=s[0][1]=s[1][0]=s[1][1]=-inf;}
    Matrix(int a,int b,int c,int d){s[0][0]=a,s[0][1]=b,s[1][0]=c,s[1][1]=d;}
};
il Matrix operator*(const Matrix&a,const Matrix&b){return Matrix(std::max(a.s[0][0]+b.s[0][0],a.s[0][1]+b.s[1][0]),std::max(a.s[0][0]+b.s[0][1],a.s[0][1]+b.s[1][1]),std::max(a.s[1][0]+b.s[0][0],a.s[1][1]+b.s[1][0]),std::max(a.s[1][0]+b.s[0][1],a.s[1][1]+b.s[1][1]));}
#define maxn 1000010
int V[maxn];
int ch[maxn][2],fa[maxn];
int fir[maxn],dis[maxn<<1],nxt[maxn<<1],id;
il vd link(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
int dp[maxn][2];
Matrix f[maxn],g[maxn];
il vd dfs(int x){
    dp[x][1]=V[x];
    for(int i=fir[x];i;i=nxt[i]){
        if(fa[x]==dis[i])continue;
        fa[dis[i]]=x;
        dfs(dis[i]);
        dp[x][0]+=std::max(dp[dis[i]][0],dp[dis[i]][1]);
        dp[x][1]+=dp[dis[i]][0];
    }
    g[x].s[0][0]=g[x].s[0][1]=dp[x][0];
    g[x].s[1][0]=dp[x][1];
}
il bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
il vd upd(int x){
    f[x]=g[x];
    if(ch[x][0])f[x]=f[ch[x][0]]*f[x];
    if(ch[x][1])f[x]=f[x]*f[ch[x][1]];
}
il vd rotate(int x){
    int y=fa[x],z=fa[y],o=x==ch[y][1];
    if(!isrt(y))ch[z][y==ch[z][1]]=x;fa[x]=z;
    ch[y][o]=ch[x][!o],fa[ch[x][!o]]=y;
    ch[x][!o]=y,fa[y]=x;upd(y);
}
il vd splay(int x){
    int y,z;
    while(!isrt(x)){
        y=fa[x],z=fa[y];
        if(!isrt(y))rotate(((x==ch[y][1])==(y==ch[z][1]))?y:x);
        rotate(x);
    }
    upd(x);
}
il vd access(int x){
    for(int y=0;x;x=fa[y=x]){
        splay(x);
        if(ch[x][1])g[x].s[0][0]+=std::max(f[ch[x][1]].s[0][0],f[ch[x][1]].s[1][0]),g[x].s[1][0]+=f[ch[x][1]].s[0][0];
        if(y)g[x].s[0][0]-=std::max(f[y].s[0][0],f[y].s[1][0]),g[x].s[1][0]-=f[y].s[0][0];
        g[x].s[0][1]=g[x].s[0][0];ch[x][1]=y;
        upd(x);
    }
}
int main(){
    int n=gi(),m=gi(),a,b;
    for(int i=1;i<=n;++i)V[i]=gi();
    for(int i=1;i<n;++i)a=gi(),b=gi(),link(a,b),link(b,a);
    dfs(1);
    int lst=0;
    while(m--){
        a=gi()^lst,b=gi();
        access(a),splay(a);
        g[a].s[1][0]+=b-V[a];upd(a);V[a]=b;
        splay(1),printf("%d\n",lst=std::max(f[1].s[0][0],f[1].s[1][0]));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xzz_233/p/10023143.html