Luogu P3647 [APIO2014]连珠线

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P3647 [APIO2014]连珠线相关的知识,希望对你有一定的参考价值。

题目
换根dp。
显然对于给定的一棵有根树,蓝线都不能拐弯。
(f_{u,0})表示(u)不是蓝线中点时子树内的答案,(f_{u,1})表示(u)是蓝线中点时子树内的答案。(以(1)为根的情况下)
那么显然有(f_{u,0}=sumlimits_{vin son_u}max(f_{v,0},f_{v,1}+d_v))
(son_u)表示(u)的儿子集合,(d_u)表示((u,fa_u))的长度)
但是(f_{u,1})如何求?
我们这样考虑:穿过(u)的蓝线就一条,我们枚举这条蓝线到它的哪个儿子,这个儿子的单独算,其它的儿子的答案则和上面一样(这一部分可以直接蒯下来而不必另算)。
(f_{u,1}=f_{u,0}+maxlimits_{vin son_u}(f_{v,0}+d_v-max(f_{v,0},f_{v,1}+d_v)))
然后我们可以(O(n^2))做了对吧。
再设(g_{u,0,v})表示和上面一样的意义,并且不考虑(u)的孩子(v)情况下的答案。
显然有(g_{u,0,v}=f_{u,0}-max(f_{v,0},f_{v,1}+d_v))
(g_{u,1,t}=g_{u,0,t}+maxlimits_{vin son_uwedge v eq t}(f_{v,0}+d_v-max(f_{v,0},f_{v,1}+d_v)))
这个我们可以在每次计算(f_{u,1})时处理出((f_{v,0}+d_v-max(f_{v,0},f_{v,1}+d_v)))的最大值和次大值来计算。
然后开始换根。
还是dfs,对于(u)以及(vin son_u),我们这样计算:
(g_{u,?,v})赋给(f_{u,?}),然后把父亲的(f)以及(d_u)合并到(u)来,再统计答案。
这样我们可以保证在((1,u))这条链上,每个点都只计算了这条链以外儿子的子树的答案以及连接它自己和它的父亲的答案,即(u)(v)以外子树的答案。
具体的看看代码能够很轻松地理解。

#include<bits/stdc++.h>
#define pi pair<int,int>
#define pb push_back
using namespace std;
const int N=200003,inf=1e9;
vector<pi>E[N];int f[N][2],fa[N],d[N],ans;vector<int>son[N],g[N][2],mx[N];
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
int max(int a,int b){return a>b? a:b;}
int min(int a,int b){return a<b? a:b;}
void dfs(int u)
{
    int mx1=-inf,mx2=-inf,x;
    for(auto [v,w]:E[u])
    {
    if(v==fa[u]) continue;
    d[v]=w,fa[v]=u,son[u].pb(v),dfs(v),f[u][0]+=max(f[v][0],f[v][1]+w),x=f[v][0]+w-max(f[v][0],f[v][1]+w); 
    if(x>mx1) mx2=mx1,mx1=x; else if(x>mx2) mx2=x;
    }
    f[u][1]=f[u][0]+mx1;
    for(auto [v,w]:E[u])
    {
    if(v==fa[u]) continue;
    g[u][0].pb(f[u][0]-max(f[v][0],f[v][1]+w)),x=f[v][0]+w-max(f[v][0],f[v][1]+w);
    x==mx1? (g[u][1].pb(g[u][0].back()+mx2),mx[u].pb(mx2)):(g[u][1].pb(g[u][0].back()+mx1),mx[u].pb(mx1));
    }
}
void dp(int u)
{
    for(int i=0;i<son[u].size();++i)
    {
        f[u][0]=g[u][0][i],f[u][1]=g[u][1][i];
        if(fa[u]) f[u][0]+=max(f[fa[u]][0],f[fa[u]][1]+d[u]),f[u][1]=f[u][0]+max(mx[u][i],f[fa[u]][0]+d[u]-max(f[fa[u]][0],f[fa[u]][1]+d[u]));
        ans=max(ans,f[son[u][i]][0]+max(f[u][0],f[u][1]+d[son[u][i]])),dp(son[u][i]);
    }
}
int main()
{
    int i,n,u,v,w;n=read();
    for(i=1;i<n;++i) u=read(),v=read(),w=read(),E[u].pb(pi(v,w)),E[v].pb(pi(u,w));
    dfs(1),dp(1),cout<<ans;
}

以上是关于Luogu P3647 [APIO2014]连珠线的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3677[Apio2014]连珠线 换根DP

[Bzoj3677][Apio2014]连珠线(树形dp)

[APIO2014]连珠线

bzoj3677: [Apio2014]连珠线

APIO2014 连珠线

动态规划小练

(c)2006-2024 SYSTEM All Rights Reserved IT常识