Luogu4719 【模板】"动态 DP"&动态树分治

https://www.luogu.com.cn/problem/P4719

动态DP

考虑静态的\(DP\)

\(f_{u,0}\)表示\(u\)号点不取时,以\(u\)为子树的最大权独立集的权值,\(f_{u,1}\)表示\(u\)号点取时,以\(u\)为子树的最大权独立集的权值

\[f_{u,0}=\sum_{v \in son_u} \max(f_{v,0},f_{v,1})\\ f_{u,1}=\sum_{v \in son_u} f_{v,0}+val_u \]

我们进行轻重链剖分,设\(w\)\(u\)的重儿子

\(g_{u,0}\)表示\(u\)的轻儿子可取可不取,且\(u\)不能取的最大权值,\(g_{u,1}\)表示\(u\)的轻儿子不取,且\(u\)必取的最大权值

\[f_{u,0}=g_{u,0}+\max(f_{w,0},f_{w,1})\\ f_{u,1}=g_{u,1}+f_{w,0} \]

为了加快运算,我们重新定义矩阵乘法的运算

\[C_{i,j}=\max(A_{i,k}+B_{k,j}) \]

转化式子

\[f_{u,0}=\max(g_{u,0}+f_{w,0},g_{u,0}+f_{w,1})\\ f_{u,1}=\max(g_{u,1}+f_{w,0},-\infty+f_{w,1}) \]

建立矩阵

\[\begin{vmatrix} f_{w,0} & f_{w,1} \end{vmatrix} \times \begin{vmatrix} g_{u,0} & g_{u,0} \\ g_{u,1} & -\infty \end{vmatrix} = \begin{vmatrix} f_{u,0} & f_{u,1} \end{vmatrix} \]

由于\(dfn\)序中,叶子节点在后,我们转换一下运算顺序

\[\begin{vmatrix} g_{u,0} & g_{u,0} \\ g_{u,1} & -\infty \end{vmatrix} \times \begin{vmatrix} f_{w,0} \\ f_{w,1} \end{vmatrix} = \begin{vmatrix} f_{u,0} \\ f_{u,1} \end{vmatrix} \]

叶子节点的矩阵\(f\)能够预处理

\[\begin{vmatrix} 0 \\ val_u \end{vmatrix} \]

为了方便,同样转换成\(2 \times 2\)的矩阵

\[\begin{vmatrix} 0 & -\infty \\ val_u & -\infty \end{vmatrix} \]

那么求一个子树\(u\)的最大权值,我们可以看到对于一个节点,我们维护的是\(g\)数组,那么它缺失的是重儿子的信息,所以我们要把\(u\)拉下去的重链上的矩阵相乘,取得的就是\(u\)的信息,所以我们需要记录每条重链的末端

考虑修改如何处理

对于一条重链上的点,直接单点修改,因为转移矩阵与重儿子无关

然后我们走到一条重链的顶端,对于它的父亲来说,这就是轻儿子了,我们直接除去原有的贡献,加入新的贡献即可

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100005
#define M 200005
#define INF 1000000007
using namespace std;
int n,m,tot,x,y,cnt;
int fr[N],fa[N],ed[N],son[N],sz[N],T[N],dfn[N],id[N],q[N],nxt[M],d[M];
int ss[N];
int f[N][2],g[N][2];
struct mat
{
    int r[2][2];
}kz[N],t[N << 2];
mat operator * (mat a,mat b)
{
    mat c;
    for (int i=0;i<2;i++)
        for (int j=0;j<2;j++)
            c.r[i][j]=-INF;
    for (int k=0;k<2;k++)
        for (int i=0;i<2;i++)
            for (int j=0;j<2;j++)
                c.r[i][j]=max(c.r[i][j],a.r[i][k]+b.r[k][j]);
    return c;
}
void add(int x,int y)
{
    tot++;
    d[tot]=y;
    nxt[tot]=fr[x];
    fr[x]=tot;
}
void dfs1(int u)
{
    int mx=-1;
    sz[u]=1;
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d[i];
        if (v==fa[u])
            continue;
        fa[v]=u;
        dfs1(v);
        sz[u]+=sz[v];
        if (sz[v]>mx)
        {
            mx=sz[v];
            son[u]=v;
        }
    }
}
void dfs2(int u,int tp)
{
    g[u][0]=0,g[u][1]=q[u];
    dfn[++cnt]=u;
    id[u]=cnt;
    T[u]=tp;
    if (!son[u])
    {
        int v=u;
        while (v!=tp)
        {
            ed[v]=id[u];
            v=fa[v];
        }
        ed[v]=id[u];
        kz[u].r[0][0]=g[u][0];
        kz[u].r[1][0]=g[u][1];
        kz[u].r[0][1]=kz[u].r[1][1]=-INF;
        f[u][0]=0,f[u][1]=q[u];
        return;
    }
    dfs2(son[u],tp);
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d[i];
        if (v==fa[u] || v==son[u])
            continue;
        dfs2(v,v);
        g[u][0]+=max(f[v][0],f[v][1]);
        g[u][1]+=f[v][0];
    }
    f[u][0]=g[u][0]+max(f[son[u]][0],f[son[u]][1]);
    f[u][1]=g[u][1]+f[son[u]][0];
    kz[u].r[0][0]=kz[u].r[0][1]=g[u][0];
    kz[u].r[1][0]=g[u][1];
    kz[u].r[1][1]=-INF;
}
#define ls (p << 1)
#define rs ((p << 1) | 1)
void build(int p,int l,int r)
{
    if (l==r)
    {
        t[p]=kz[dfn[l]];
        ss[l]=p;
        return;
    }
    int mid=(l+r) >> 1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    t[p]=t[ls]*t[rs];
}
void change(int p)
{
    if (!p)
        return;
    t[p]=t[ls]*t[rs];
    change(p >> 1);
}
mat calc(int p,int l,int r,int x,int y)
{
    if (l==x && r==y)
        return t[p];
    int mid=(l+r) >> 1;
    if (y<=mid)
        return calc(ls,l,mid,x,y); else
    if (x>mid)
        return calc(rs,mid+1,r,x,y); else
        return calc(ls,l,mid,x,mid)*calc(rs,mid+1,r,mid+1,y);
}
void update(int x,int y)
{
    kz[x].r[1][0]+=y-q[x];
    q[x]=y;
    while (x)
    {
        mat bef,aft;
        bef=calc(1,1,n,id[T[x]],ed[T[x]]);
        t[ss[id[x]]]=kz[x];
        change(ss[id[x]] >> 1);
        aft=calc(1,1,n,id[T[x]],ed[T[x]]);
        int u=fa[T[x]];
        if (!u)
            break;
        kz[u].r[0][0]-=max(bef.r[0][0],bef.r[1][0]);
        kz[u].r[0][0]+=max(aft.r[0][0],aft.r[1][0]);
        kz[u].r[0][1]=kz[u].r[0][0];
        kz[u].r[1][0]-=bef.r[0][0];
        kz[u].r[1][0]+=aft.r[0][0];
        x=u;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&q[i]);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs1(1);
    dfs2(1,1);
    build(1,1,n);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        update(x,y);
        mat ans=calc(1,1,n,id[1],ed[1]);
        printf("%d\n",max(ans.r[0][0],ans.r[1][0]));
    }
    return 0;
}
posted @ 2020-09-02 15:23  GK0328  阅读(208)  评论(0编辑  收藏  举报