2019.01.04 洛谷P4719 【模板】动态dp(链分治+ddp)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/85796782

传送门
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[p]=val[l];
        return;
    }
    build(lc,l,mid),build(rc,mid+1,r),T[p]=T[lc]*T[rc];
}
inline void update(int p,int l,int r,int k){
    if(l==r){T[p]=val[l];return;}
    if(k<=mid)update(lc,l,mid,k);
    else update(rc,mid+1,r,k);
    T[p]=T[lc]*T[rc];
}
inline Mat query(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return T[p];
    if(qr<=mid)return query(lc,l,mid,ql,qr);
    if(ql>mid)return query(rc,mid+1,r,ql,qr);
    return query(lc,l,mid,ql,mid)*query(rc,mid+1,r,mid+1,qr);
}
inline Mat ask(int p){return query(1,1,n,num[top[p]],bot[top[p]]);}
inline Mat change(int p,int x){
    val[num[p]].g[1][0]+=x-a[p],a[p]=x;
    Mat od,nw;
    while(p){
        od=ask(top[p]),update(1,1,n,num[p]),nw=ask(top[p]),p=fa[top[p]];
        val[num[p]].g[0][0]+=max(nw.g[0][0],nw.g[1][0])-max(od.g[0][0],od.g[1][0]);
        val[num[p]].g[0][1]=val[num[p]].g[0][0];
        val[num[p]].g[1][0]+=nw.g[0][0]-od.g[0][0];
    }
    return ask(1);
}
inline int read(){
    int ans=0,w=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans*w;
}
int main(){
    n=read(),m=read();
    for(ri i=1;i<=n;++i)a[i]=read();
    for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs1(1),dfs2(1,1),build(1,1,n);
    while(m--){
        int x=read(),y=read();
        Mat ret=change(x,y);
        cout<<max(ret.g[0][0],ret.g[1][0])<<'\n';
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/85796782