换根DP

引入

换根DP,又叫二次扫描,是树形DP的一种。

其相比于一般的树形DP具有以下特点:

1.以树上的不同点作为根,其解不同。
2.故为求解答案,不能单求某点的信息,需要求解每个节点的信息。
2.故无法通过一次搜索完成答案的求解,因为一次搜索只能得到一个节点的答案。

经典题

P3478 [POI2008]STA-Station

给定一个n个点的无根树,问以树上哪个节点为根时,其所有节点的深度和最大?

sol:

AC码

int dep[Max],siz[Max],ans[Max];
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1;
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(fa==v) continue;
        dfs(v,u);
        siz[u]+=siz[v];
    }
}
void dfs1(int u,int fa)
{
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(fa==v) continue;
        ans[v]=ans[u]-siz[v]+(siz[1]-siz[v]);
        dfs1(v,u);
    }
}
signed main()
{
    n=rd;
    pos(i,1,n-1)
    {
        int x=rd,y=rd;
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    pos(i,1,n) ans[1]+=dep[i];
    dfs1(1,0);
    int res=0,re=0;
    pos(i,1,n)
    {
        if(res<=ans[i]) 
        {
            res=ans[i];
            re=i;
        }
    }
    printf("%lld\n",re);
    return 0;
}

P2986 [USACO10MAR]Great Cow Gathering G

sol:与上题相似

AC码

int dep[Max],siz[Max],ans[Max];
int val[Max];

void dfs(int u,int fa,int d)
{
    dep[u]=dep[fa]+d;
    siz[u]=val[u];
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u,e[i].l);
        siz[u]+=siz[v];
    }
}

void dfs1(int u,int fa)
{
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa)continue;
        ans[v]=ans[u]+((siz[1]-siz[v])-siz[v])*e[i].l;
        dfs1(v,u);
    }
}

signed main()
{
    n=rd;
    pos(i,1,n) val[i]=rd;
    pos(i,1,n-1) 
    {
        int x=rd,y=rd,z=rd;
        add(x,y,z),add(y,x,z);
    }
    dfs(1,0,0);
    pos(i,1,n) ans[1]+=dep[i]*val[i];
    dfs1(1,0);
    int res=inf;
    pos(i,1,n) res=min(res,ans[i]);
    printf("%lld\n",res);
    return 0;
}

CF1324F Maximum White Subtree

题目大意:一棵树,节点有黑有白,从某节点出发,遇黑-1,遇白+1。

问:从每个节点出发,能得到的最大值是多少?

sol:

AC码

int n;
int a[Max],f[Max],ans[Max];
vector<int>e[Max];
void dfs(int u,int fa)
{
    f[u]=(a[u]==1?1:-1);
    for(auto v:e[u])
    {
        if(v==fa)continue;
        dfs(v,u);
        f[u]+=max(0,f[v]);
    }
}
void dfs1(int u,int fa)
{
    for(auto v:e[u])
    {
        if(fa==v)continue;
        ans[v]=max(0,ans[u]-max(0,f[v]))+f[v];
        dfs1(v,u);
    }
}
int main()
{
    n=rd;
    pos(i,1,n) a[i]=rd;
    pos(i,1,n-1)
    {
        int x=rd,y=rd;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(1,0);
    ans[1]=f[1];
    dfs1(1,0);
    pos(i,1,n) printf("%d ",ans[i]);
	return 0;
}

待练习题

P3047 [USACO12FEB]Nearby Cows G

CF708C Centroids

学习博客

https://zhuanlan.zhihu.com/p/348349531

posted @ 2021-11-03 12:12  juuich  阅读(91)  评论(0编辑  收藏  举报