洛谷P4719 【模板】动态dp

题目链接

ddp就是通过加法对min/max的分配率把原来不好维护的dp转移搞成可以遵循分配率的矩阵形式,自然就以用一些数据结构去维护
比如说这题求最大权独立集
先写出转移方程
dp[u][0/1]表示该点取或者不取时该点为根的子树的最大权独立集
dp[u][0]= \sum max(dp[v][0],dp[v][1])
dp[u][1]=( \sum dp[v][0]) +val[u]
数据结构维护的话就是LCT或者树链剖分
LCT好久不写了懒得写,就想想树剖吧
考虑线段树上查询的一个区间关系大抵是父亲和重儿子
那么就令g[u][0]表示该点不选时除重儿子以外的dp值之和
g[u][0]= ( v s o n ) \sum(v\neq son) max(dp[v][0],dp[v][1])
g[u][1]=( ( v s o n ) \sum(v\neq son) dp[v][0])+val[u]
重写转移方程
dp[u][0]=max(dp[son][0],dp[son][1])+g[u][0]
dp[u][1]=dp[son][0]+g[u][1]
写出矩阵
[ g [ u ] [ 0 ] g [ u ] [ 0 ] g [ u ] [ 1 ] ] [ d p [ s o n ] [ 0 ] d p [ s o n ] [ 1 ] ] = [ d p [ u ] [ 0 ] d p [ u ] [ 1 ] ] \left[ \begin{matrix} g[u][0]& g[u][0] \\ g[u][1] & -\infty \end{matrix} \right] \left[ \begin{matrix} dp[son][0] \\ dp[son][1] \end{matrix} \right]= \left[ \begin{matrix} dp[u][0] \\ dp[u][1] \end{matrix} \right]
显然每次的答案都是max(dp[1][0],dp[1][1])
更新的话,每次显然只会改变log个从一条链跳入另一条链的g值
所以直接按照跳top的父亲,改,再跳,再改,这样的套路就可以了
跳的复杂度是log,修改是log总复杂度两只log
用LCT或者GBT可以弄到一只log,但博主太菜并不会

代码又臭又长

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define lson root<<1
#define rson root<<1|1
#define N 400040
using namespace std;

struct matrix
{
    int a[2][2];
    matrix()
    {
        a[0][0]=a[0][1]=a[1][0]=a[1][1]=-inf;
    }
}m[N];

inline void mx(int &a,const int &b)
{
    if(a<b) a=b;
}

void print(matrix a)
{
    for(int i=0;i<=1;i++)
    {
        for(int j=0;j<=1;j++)
        {
            printf("%d ",a.a[i][j]);
        }
        puts("");
    }
}

matrix mul(matrix a,matrix b)
{
    matrix c;
    for(int i=0;i<=1;i++)
    {
        for(int j=0;j<=1;j++)
        {
            for(int k=0;k<=1;k++)
            {
                mx(c.a[i][j],a.a[i][k]+b.a[k][j]);
            }
        }
    }
    return c;
}

vector<int> g[N];
int l[N],r[N],p[N];
int gg[N][2],f[N][2],idn[N],id[N],top[N],fa[N],sz[N],son[N],v[N],w[N],ed[N],cnt;

void push_up(int root)
{
    m[root]=mul(m[lson],m[rson]);
}

void build(int root,int ll,int rr)
{
    l[root]=ll,r[root]=rr;
    if(ll==rr)
    {
    	m[root].a[0][0]=m[root].a[0][1]=gg[idn[ll]][0];
    	m[root].a[1][0]=gg[idn[ll]][1];
    	p[ll]=root;
        return ;
    }
    int mid=(ll+rr)>>1;
    build(lson,ll,mid);
    build(rson,mid+1,rr);
    push_up(root);
}

void update(int root,int pos,int val)
{
    if(l[root]==r[root])
    {
        m[root].a[1][0]+=val-w[l[root]];
        w[l[root]]=val;
        return ;
    }
    int mid=(l[root]+r[root])>>1;
    if(pos<=mid)
    {
        update(lson,pos,val);
    }
    else
    {
        update(rson,pos,val);
    }
    push_up(root);
}

void update2(int root,int pos,int val1,int val2,int val3,int val4)
{
	if(pos<1) return;
	if(l[root]==r[root])
	{
		m[root].a[0][0]+=val2-val1;
		m[root].a[0][1]=m[root].a[0][0];
		m[root].a[1][0]+=val4-val3;
		return ;
	}
	int mid=(l[root]+r[root])>>1;
    if(pos<=mid)
    {
        update2(lson,pos,val1,val2,val3,val4);
    }
    else
    {
        update2(rson,pos,val1,val2,val3,val4);
    }
    push_up(root);
}

matrix query(int root,int ll,int rr)
{
    if(ll<=l[root]&&r[root]<=rr)
    {
        return m[root];
    }
    int mid=(l[root]+r[root])>>1;
    if(rr<=mid)
    {
        return query(lson,ll,rr);
    }
    else
    {
        if(mid<ll)
        {
            return query(rson,ll,rr);
        }
        return mul(query(lson,ll,mid),query(rson,mid+1,rr));
    }
}

void dfs1(int now,int f)
{
    fa[now]=f;
    sz[now]=1;
    int maxson=-1;
    for(int i=0;i<g[now].size();i++)
    {
        if(g[now][i]==f) continue;
        dfs1(g[now][i],now);
        sz[now]+=sz[g[now][i]];
        if(sz[g[now][i]]>maxson)
        {
            maxson=sz[g[now][i]];
            son[now]=g[now][i];
        }
    }
}

void dfs2(int now,int tp)
{
    id[now]=++cnt;
    top[now]=tp;
    w[cnt]=v[now];
    idn[cnt]=now;
    if(!son[now]) {f[now][1]=v[now],gg[now][1]=v[now],ed[now]=now;return ;}
    dfs2(son[now],tp);
    for(int i=0;i<g[now].size();i++)
    {
        if(g[now][i]==fa[now]||g[now][i]==son[now]) continue;
        dfs2(g[now][i],g[now][i]);
        gg[now][0]+=max(f[g[now][i]][0],f[g[now][i]][1]);
        gg[now][1]+=f[g[now][i]][0];
    }
    gg[now][1]+=v[now];
    f[now][0]=gg[now][0]+max(f[son[now]][0],f[son[now]][1]);
    f[now][1]=gg[now][1]+f[son[now]][0];
    ed[now]=ed[son[now]];
}

void change(int now,int val)
{
	int max1,max2,f1,f2;
    matrix pre=query(1,id[top[now]],id[ed[now]]);
    update(1,id[now],val);
    matrix c=query(1,id[top[now]],id[ed[now]]);
    now=fa[top[now]];
    max1=max(pre.a[1][0],pre.a[0][0]);
    max2=max(c.a[1][0],c.a[0][0]);
    f1=pre.a[0][0];
    f2=c.a[0][0];
    while(top[now])
    {
    	pre=query(1,id[top[now]],id[ed[now]]);
    	update2(1,id[now],max1,max2,f1,f2);
    	c=query(1,id[top[now]],id[ed[now]]);
    	max1=max(pre.a[1][0],pre.a[0][0]);
    	max2=max(c.a[1][0],c.a[0][0]);
    	f1=pre.a[0][0];
    	f2=c.a[0][0];
    	now=fa[top[now]];
    }
}

int n,q;

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
    }   
    int from,to;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&from,&to);
        g[from].push_back(to);
        g[to].push_back(from);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,cnt);
    int pp,vv;
    matrix tmp;
    for(int i=1;i<=q;i++)
    {
    	scanf("%d%d",&pp,&vv);
    	change(pp,vv);
    	tmp=query(1,id[top[1]],id[ed[1]]);
    	printf("%d\n",max(tmp.a[0][0],tmp.a[1][0]));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_21829533/article/details/87922690