1. 程式人生 > >P4719 【模板】動態dp

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;
}