牛客周赛 Round 15 D 游游的树上边染红(树形dp)

 一道很裸的树形dp,周日晚上看了一晚上看不懂,第二天突然就悟了。
 题目跟没有上司从舞会很像,我们粗略的考虑,当前节点的状态为选/不选,然后根据此进行状态转移。
不选择当前点: 
     
      
       
       
         d 
        
       
         p 
        
       
         [ 
        
       
         u 
        
       
         ] 
        
       
         [ 
        
       
         0 
        
       
         ] 
        
       
      
        dp[u][0] 
       
      
    dp[u][0],表示我不选以节点 u 为上节点的边,那么对于 u 的所有子节点,我选择其状态的最大值即可。
即:
  
      
       
        
        
          d 
         
        
          p 
         
        
          [ 
         
        
          u 
         
        
          ] 
         
        
          [ 
         
        
          0 
         
        
          ] 
         
        
          + 
         
        
          = 
         
        
          m 
         
        
          a 
         
        
          x 
         
        
          ( 
         
        
          d 
         
        
          p 
         
        
          [ 
         
        
          v 
         
        
          ] 
         
        
          [ 
         
        
          0 
         
        
          ] 
         
        
          , 
         
        
          d 
         
        
          p 
         
        
          [ 
         
        
          v 
         
        
          ] 
         
        
          [ 
         
        
          1 
         
        
          ] 
         
        
          ) 
         
        
          , 
         
        
          v 
         
        
          为 
         
        
          u 
         
        
          的子节点 
         
        
       
         dp[u][0]+=max(dp[v][0],dp[v][1]),v为u的子节点 
        
       
     dp[u][0]+=max(dp[v][0],dp[v][1]),v为u的子节点
选择当前点: d p [ u ] [ 1 ] dp[u][1] dp[u][1],表示我选择了以节点 u 为上节点的边,则需要去对 u 与其所有子节点的边进行遍历,取最大值即可。
d p [ x ] [ 1 ] = m a x ( d p [ x ] [ 1 ] , d p [ x ] [ 0 ] − m a x ( d p [ u ] [ 0 ] , d p [ u ] [ 1 ] ) + d p [ u ] [ 0 ] + w ) dp[x][1]=max(dp[x][1],dp[x][0]-max(dp[u][0],dp[u][1])+dp[u][0]+w) dp[x][1]=max(dp[x][1],dp[x][0]−max(dp[u][0],dp[u][1])+dp[u][0]+w)
该方程的状态转移解释为:我若是选择了该边,那么对于子节点 v ,我只能取其不选的状态,即 d p [ v ] [ 0 ] dp[v][0] dp[v][0],而又因为我是选择的 u − v i u-v_i u−vi这条边,所以不影响 u 对于其他边的选择,我只需要对其他子节点的状态依旧取 max 即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;
// #define endl "\n"
int n;
vector<pll> e[N];
void add(int u,int v,int w)
{
	e[u].push_back({v,w});
	e[v].push_back({u,w});
}
ll dp[N][2];
void dfs(int x,int f)
{
	ll sum=0;
	for(auto [u,w]: e[x]){
		if(u!=f){
            dfs(u,x);
			dp[x][0]+=max(dp[u][0],dp[u][1]);
			//sum+=max(dp[u][0],dp[u][1]);
		}
	}
	for(auto [u,w]: e[x]){
        if(u!=f)
		dp[x][1]=max(dp[x][1],dp[x][0]-max(dp[u][0],dp[u][1])+dp[u][0]+w);
	}
    //cout<<dp[x][0]<<" "<<dp[x][1]<<endl;
}
void solve()
{	
	cin>>n;
	for(int i=1;i<=n-1;i++){
		ll u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
	}
	dfs(1,-1);
	cout<<max(dp[1][0],dp[1][1])<<endl;
}
int main()
{
    ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	//cin>>t;
	while(t--){
		solve();
	}
    system("pause");
    return 0;
}
                


















