【洛谷P4719】【模板】动态 DP

题目

题目链接:https://www.luogu.com.cn/problem/P4719
给定一棵\(n\)个点的树,点带点权。
\(m\)次操作,每次操作给定\(x,y\),表示修改点\(x\)的权值为\(y\)
你需要在每次操作之后求出这棵树的最大权独立集的权值大小。

思路

调到心态爆炸。。。从前天晚上开始就刚这道题。。。
最大权独立子集即“选出若干个不相邻的点使得他们的权值最大”。——摘自AKIOI的神仙
若没有修改,这道题就是树形\(dp\)入门题,设\(f[x][0/1]\)表示以\(x\)为根的子树,节点\(i\)选不选的最大权独立子集。那么有转移
\[f[u][0]=\sum_{v\in u's\ son}max(f[v][0],f[v][1])\]
\[f[u][1]=\sum_{v\in u's\ son}f[v][0]\]
\(ddp\)是维护序列问题的,我们考虑将这棵树剖一下,变成若干条重链计算。
那么既然我们重链用矩阵乘法维护,那么轻链就要先计算出来。设\(g[x][0/1]\)表示不看\(x\)的重儿子的最大权独立子集,转移显然。
这样我们就可以改写\(f\)的转移
\[f[u][0]=g[u][0]+max(f[v][0],f[v][1])\]
\[f[u][1]=g[u][1]+f[v][0]\]
其中\(v\)\(u\)的重儿子。
写成矩阵,有
\[\begin{bmatrix}f[v][0] \\ f[v][1] \end{bmatrix} \begin{bmatrix} g[u][0] &g[u][0] \\ g[u][1] &-\infty \end{bmatrix} = \begin{bmatrix} f[u][0]\\ f[u][1] \end{bmatrix}\]
假设我们修改点\(x\),这样我们就可以修改\(g[top[x]]\),然后再利用\(g[top[x]]\)修改\(g[fa[top[x]]]\),再利用重链往上修改。
细节算是比较多吧,调的很恶心。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100010,Inf=107374323;
int head[N],a[N],f[N][2],g[N][2],son[N],rk[N],id[N],top[N],size[N],fa[N],end[N];
int n,Q,tot;

struct edge
{
    int next,to;
}e[N*2];

void add(int from,int to)
{
    e[++tot].to=to;
    e[tot].next=head[from];
    head[from]=tot;
}

void dfs1(int x,int father)
{
    f[x][0]=0; f[x][1]=a[x];
    size[x]=1; fa[x]=father;
    for (int i=head[x];~i;i=e[i].next)
    {
        int v=e[i].to;
        if (v!=father)
        {
            dfs1(v,x);
            size[x]+=size[v];
            f[x][0]+=max(f[v][0],f[v][1]);
            f[x][1]+=f[v][0];
            if (size[v]>size[son[x]]) son[x]=v;
        }
    }
}

void dfs2(int x,int tp)
{
    g[x][0]=0; g[x][1]=a[x];
    id[x]=++tot; rk[tot]=x; top[x]=tp; end[tp]=tot;
    if (son[x]) dfs2(son[x],tp);
    for (int i=head[x];~i;i=e[i].next)
    {
        int v=e[i].to;
        if (v!=fa[x] && v!=son[x])
        {
            dfs2(v,v);
            g[x][0]+=max(f[v][0],f[v][1]);
            g[x][1]+=f[v][0];
        }
    }
}

struct matrix
{
    int a[3][3];
    
    matrix()
    {
        a[1][1]=a[1][2]=a[2][1]=a[2][2]=-Inf;
    }
    
    friend matrix operator *(matrix a,matrix b)
    {
        matrix c;
        for (int i=1;i<=2;i++)
            for (int j=1;j<=2;j++)
                for (int k=1;k<=2;k++)
                    c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
        return c;
    }
}M[N];

struct SegTree
{
    int l[N*4],r[N*4];
    matrix f[N*4];
    
    void pushup(int x)
    {
        f[x]=f[x*2]*f[x*2+1];
    }
    
    void build(int x,int ql,int qr)
    {
        l[x]=ql; r[x]=qr;
        if (ql==qr)
        {
            f[x]=M[rk[ql]];
            return;
        }
        int mid=(l[x]+r[x])>>1;
        build(x*2,ql,mid); build(x*2+1,mid+1,qr);
        pushup(x);
    }
    
    matrix ask(int x,int ql,int qr)
    {
        if (l[x]==ql && r[x]==qr) return f[x];
        int mid=(l[x]+r[x])>>1;
        if (qr<=mid) return ask(x*2,ql,qr);
        if (ql>mid) return ask(x*2+1,ql,qr);
        return ask(x*2,ql,mid)*ask(x*2+1,mid+1,qr);
    }
    
    void update(int x,int k)
    {
        if (l[x]==k && r[x]==k)
        {
            f[x]=M[rk[k]];
            return;
        }
        int mid=(l[x]+r[x])>>1;
        if (k<=mid) update(x*2,k);
            else update(x*2+1,k);
        pushup(x);
    }
}seg;

void Update(int x,int val)
{
    M[x].a[2][1]=M[x].a[2][1]-a[x]+val;
    a[x]=val;
    while (x)
    {
        matrix last=seg.ask(1,id[top[x]],end[top[x]]);
        seg.update(1,id[x]);
        matrix now=seg.ask(1,id[top[x]],end[top[x]]);
        x=fa[top[x]];
        M[x].a[1][1]=M[x].a[1][2]=M[x].a[1][1]-max(last.a[1][1],last.a[2][1])+max(now.a[1][1],now.a[2][1]);
        M[x].a[2][1]=M[x].a[2][1]-last.a[1][1]+now.a[1][1];
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&Q);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    tot=0;
    dfs1(1,0); dfs2(1,1);
    for (int i=1;i<=n;i++)
    {
        M[i].a[1][1]=M[i].a[1][2]=g[i][0];
        M[i].a[2][1]=g[i][1];
        M[i].a[2][2]=-Inf;
    }
    seg.build(1,1,n);
    while (Q--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Update(x,y);
        matrix ans=seg.ask(1,id[1],end[1]);
        printf("%d\n",max(ans.a[1][1],ans.a[2][1]));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/stoorz/p/12303203.html