P9 CF2050G Tree Destruction

CF Round 991 (div.3) G

十分经典的树形DP,但是我却对此十分畏惧...

​ 这题思路上没什么好说的,很容易就能想到用DP。要说麻烦,主要可能就是理清树上的链和点之间的关系,方便构造转移方程。

​ 对于以 \(pos\) 为根的子树,如果我们要找一条链在此子树中,那本质上就是两个状态:\(pos\) 在链上或者不在。不过对于本题由于只选择一条链,所以可以将 \(pos\) 在链上的情况转化成 \(pos\) 在链端点和不在端点。这样在 DFS 的时候方便转移。

const int N=200010;

int n,f[N][3],_out[N];//不在,端点,中间(只需考虑以pos为根的子树)
vector<int> G[N];

inline void dfs(int pos,int fafa){
  f[pos][0]=f[pos][1]=1;
  int mx1=0,mx2=0;
  for(int to:G[pos]){
    if(to==fafa) continue;
    dfs(to,pos);
    f[pos][0]=max(f[pos][0],max({f[to][0],f[to][1]+1,f[to][2]+1}));
    f[pos][1]=max(f[pos][1],f[to][1]);
    if(f[to][1]>mx1) mx2=mx1,mx1=f[to][1];
    else if(f[to][1]>mx2) mx2=f[to][1];
  }
  f[pos][1]+=_out[pos]-2;
  if(mx1&&mx2) f[pos][2]=mx1+mx2+_out[pos]-3;
}

inline void solve(){
  memset(f,0,sizeof(f));
  dfs(1,1);
  cout<<max({f[1][0],f[1][1]+1,f[1][2]+1})<<'\n';
}

signed main(){
  IOS
  int T;
  cin>>T;
  while(T--){
    cin>>n;
    for(int i=1;i<=n;++i)
      G[i].clear(),_out[i]=0;
    for(int i=1;i<n;++i){
      int fo,to;
      cin>>fo>>to;
      G[fo].pb(to),G[to].pb(fo);
      _out[fo]++,_out[to]++;
    } solve();
  }

  return 0;
}

​ 我写的代码中需要注意的是,在状态转移时出入度值的变化,由于 DFS 中不需要考虑父节点,但是回溯时又得考虑。并且根节点不存在父节点,所以我卡了半天......

​ · EOF

posted @ 2025-01-09 18:48  ComplexityMFC  阅读(27)  评论(0)    收藏  举报