BZOJ 3677: [Apio2014]连珠线 树形DP

倒在了性质分析上....(还有仔细读题)

仔细读题后,我们发现红色边只能连接一个连通块和一个叶节点(或两个叶节点).

然后如果一个状态是合法的,当且仅当以某个点为根时所有蓝边都是形如 son[x]->x->fa[x]

然后因为有这条性质,我们就可以进行树形DP了.

令 $1$ 为根,$f[x]$ 表示 $x$ 是蓝边中点时以 $x$ 为根的子树的最大价值,$g[x]$ 表示不是中点时的最大价值.

然后当根不是 $1$ 时,用换根DP的方式转移即可,需要记录一个最小/次小值跟着一起转移.

#include <cstdio>  
#include <string>
#include <cstring>
#include <algorithm>  
#define N 200007 
#define inf 1000000000 
using namespace std;    
void setIO(string s) 
{
    string in=s+".in"; 
    string out=s+".out"; 
    freopen(in.c_str(),"r",stdin); 
    // freopen(out.c_str(),"w",stdout); 
} 
int edges,n,ans;  
int f[N],g[N],hd[N],to[N<<1],nex[N<<1],val[N<<1],f1[N],f2[N];      
void add(int u,int v,int c) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; 
}
void dfs(int u,int ff) 
{   
    g[u]=0,f[u]=-inf;  
    f1[u]=f2[u]=-inf;  
    for(int i=hd[u];i;i=nex[i]) 
    {
        int v=to[i]; 
        if(v==ff) continue;   
        dfs(v,u); 
        g[u]+=max(g[v],f[v]+val[i]);                    
    }    
    for(int i=hd[u];i;i=nex[i]) 
    {
        int v=to[i]; 
        if(v==ff) continue;         
        f[u]=max(f[u],g[u]-max(g[v],f[v]+val[i])+g[v]+val[i]);   
        int tmp=g[v]+val[i]-max(g[v],f[v]+val[i]);    
        if(tmp>f1[u]) f2[u]=f1[u],f1[u]=tmp;        
        else if(tmp>f2[u]) f2[u]=tmp;      
    }
}
void dfs2(int u,int ff) 
{  
    ans=max(ans,g[u]);   
    for(int i=hd[u];i;i=nex[i]) 
    {
        int v=to[i];   
        if(v==ff) continue;     
        int gu=g[u]-max(g[v],g[v]+f1[v]+val[i]),fu;    
        if(f1[u]==g[v]+val[i]-max(g[v],g[v]+f1[v]+val[i])) fu=f2[u];     
        else fu=f1[u];   
        g[v]+=max(gu,gu+fu+val[i]);       
        fu=gu+val[i]-max(gu,gu+fu+val[i]);      
        if(fu>f1[v]) f2[v]=f1[v],f1[v]=fu;   
        else if(fu>f2[v]) f2[v]=fu; 
        dfs2(v,u);   
    }
}
int main() 
{ 
    // setIO("input");  
    int i,j,x,y,z; 
    scanf("%d",&n);  
    for(i=1;i<n;++i) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);   
    ans=-inf; 
    dfs(1,0);   
    dfs2(1,0); 
    printf("%d\n",ans); 
    return 0; 
}

  

posted @ 2020-01-02 10:40  EM-LGH  阅读(149)  评论(0编辑  收藏  举报