1. 程式人生 > >2019.01.04 洛谷P4719 【模板】動態dp(鏈分治+ddp)

2019.01.04 洛谷P4719 【模板】動態dp(鏈分治+ddp)

傳送門
d d p ddp 模板題。
題意簡述:給你一棵樹,支援修改一個點,維護整棵樹的最大帶權獨立集。


思路:
我們考慮如果沒有修改怎麼做。
貌似就是一個 s b

sb 樹形 d p dp f i ,
0 f_{i,0}
表示不選 i i 的最大值, f i
, 1 f_{i,1}
表示選 i i 的最大值。
那麼可以這樣從 i i 的兒子 v v 轉移過來:
f p , 0 + = m a x { f v , 0 , f v , 1 } , f p , 1 + = f v , 0 f_{p,0}+=max\{f_{v,0},f_{v,1}\},f_{p,1}+=f_{v,0}
然後就能夠解決靜態時候的問題。
然而現在是動態的怎麼搞呢?
有句話說得好:智商不夠資料結構來湊,這個時候就可以上樹鏈剖分辣。
我們知道有點分治這種東西,同樣也有鏈分治這種東西,也就是對於一條鏈維護其有關資訊。
對於這道題,我們考慮維護重鏈的資訊,考慮記一個 g i , 0 / 1 g_{i,0/1} 表示選/不選 i i 點時所有輕兒子的子孫的最大獨立集。
於是 f i , 0 = g i , 0 + m a x { f h s o n v , 0 , f h s o n v , 1 } , f i , 1 = g i , 1 + f h s o n v , 0 f_{i,0}=g_{i,0}+max\{f_{hson_v,0},f_{hson_v,1}\},f_{i,1}=g_{i,1}+f_{hson_v,0}

然後這個東西是可以用類似於矩陣乘法的東西轉移的,我們將矩陣的加法重定義成取 m a x max ,把矩陣的乘法重定義成加法。

然後就能夠變成下面的矩陣轉移:
( f i , 0 f i , 1 ) = ( g i , 0 g i , 0 g i , 1 ) ( f v , 0 f v , 1 ) \begin{pmatrix} f_{i,0}\\ f_{i,1}\\ \end{pmatrix}= \begin{pmatrix} g_{i,0}&g_{i,0}\\ g_{i,1}&-\infty\\ \end{pmatrix}* \begin{pmatrix} f_{v,0}\\ f_{v,1}\\ \end{pmatrix}
由於矩陣滿足結合律。
所以可以上樹剖,維護區間矩陣乘積。
修改的時候,從被修改節點開始沿著重鏈向根節點跳。對於每條重鏈,先對鏈底修改,然後更新鏈頂,然後跳到下一條重鏈繼續修改即可。
每次答案就是根節點的 f f 值。
程式碼:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define ri register int
#define mid (l+r>>1)
using namespace std;
const int N=1e5+5;
struct Mat{
    int g[2][2];
    Mat(){g[0][0]=g[0][1]=g[1][0]=g[1][1]=0;}
    friend inline Mat operator*(const Mat&a,const Mat&b){
        Mat ret;
        for(ri i=0;i<2;++i)for(ri k=0;k<2;++k)for(ri j=0;j<2;++j)ret.g[i][j]=max(ret.g[i][j],a.g[i][k]+b.g[k][j]);
        return ret;
    }
}T[N<<2],val[N];
int n,m,tot=0,siz[N],a[N],hson[N],top[N],bot[N],pred[N],num[N],f[N][2],fa[N];
vector<int>e[N];
void dfs1(int p){
    siz[p]=1,f[p][0]=0,f[p][1]=a[p];
    for(ri v,i=0;i<e[p].size();++i){
        v=e[p][i];
        if(v==fa[p])continue;
        fa[v]=p,dfs1(v),siz[p]+=siz[v];
        if(siz[v]>siz[hson[p]])hson[p]=v;
        f[p][0]+=max(f[v][0],f[v][1]),f[p][1]+=f[v][0];
    }
}
void dfs2(int p,int tp){
    top[p]=tp,pred[num[p]=++tot]=p;
    if(!hson[p]){bot[tp]=tot;return;}
    dfs2(hson[p],tp);
    for(ri v,i=0;i<e[p].size();++i){
        v=e[p][i];
        if(v!=fa[p]&&v!=hson[p])dfs2(v,v);
    }
}
inline void build(int p,int l,int r){
    if(l==r){
        int u=pred[l],g0=0,g1=a[u];
        for(ri v,i=0;i<e[u].size();++i){
            v=e[u][i];
            if(v!=hson[u]&&v!=fa[u])g0+=max(f[v][0],f[v][1]),g1+=f[v][0];
        }
        val[l].g[0][0]=val[l].g[0][1]=g0,val[l].g[1][0]=g1,val[l].g[1][1]=-0x3f3f3f3f,T