[CF1646D] Weight the Tree

[CF1646D] Weight the Tree

题意

给定一个无根树,点从 \(1\)\(n\) 编号。你需要给每个点分配一个正整数权值 \(w_i\)。定义一个节点为好节点,当且仅当其权值等于所有相邻节点的权值之和。

请最大化好节点的个数,并且在好节点个数最大的前提下最小化所有节点的权值和。

分析

我们先考虑一种特殊情况,当 \(n=2\) 时我们有唯一可以使一个点和它的父亲都为好的节点,这样我们先特判这种情况。

而后我们考虑设两个状态来转移本题。我们设 \(f_{i,10}\) 表示该点是好的节点或不好的节点子树内好的节点数(包含该点)。显然我们有一个节点和它的父亲不能同时为好的节点。而后我们显然有转移

\(f_{u,0}=sum min({f_{son[u],0},f_{son[u],1}})\)

\(f_{u,1}=sum f_{sum[u],0}\)

而后我们考虑设 \(g_{i,10}\) 表示该点是好的节点或者不好的节点子树内点权和(包含该点)。显然

\(g_{u,1}=sum g_{son[u],0}\)

\(f_{u,0}=f_{u,1}\) 时有 \(g_{u,0}=sum min(g_{son[u],0},g_{son[u],1})\)

\(f_{u,0}f_{u,1}\) 时有 \(g_{u,0}=sum f_{son[u],0}\)

\(f_{u,0}f_{u,1}\) 时有 \(g_{u,0}=sum f_{son[u],1}\)

而后我们考虑一种方案,即若该点为好的节点该点权值为 \(deg[i]\) 否则为 \(1\)。显然最优。而后我们考虑怎么标记。我们考虑再进行一次 \(mark\) 操作,如果该点的父亲被标记那么显然它肯定不能被标记,而后如果该点被该点不被标记是 \(f\) 值大或者 \(f\) 值相同 \(g\) 值更小,那么不被标记,反之被标记。而后我们下传这个标记给他的儿子,这样使得它的儿子必须不能被标记,这样 dfs 下去显然可以得出一个方案。

代码

#includebitsstdc++.h
using namespace std;
const int N=2e5+7;
int n;
vectorint G[N2];
int deg[N];
int f[N2][2],g[N2][2];
void dfs(int u,int father){
  f[u][1]=1,g[u][1]=deg[u],g[u][0]=1;
  for(int kG[u]) if(k!=father){
    dfs(k,u);
    f[u][1]+=f[k][0];
    g[u][1]+=g[k][0];
    f[u][0]+=max(f[k][0],f[k][1]);
    if(f[k][0]==f[k][1]) g[u][0]+=min(g[k][0],g[k][1]);
    else g[u][0]+=(f[k][0]f[k][1]g[k][0]g[k][1]);
  }
}
bool mrk[N];
void mark(int u,int father,bool fl){
  if(fl) mrk[u]=0;
  else{
    if(f[u][0]f[u][1]f[u][0]==f[u][1]&&g[u][0]g[u][1])
    mrk[u]=0;
    else mrk[u]=1;
  }
  for(int kG[u]){
    if(k!=father)
    mark(k,u,mrk[u]);
  }
}
int main(){
  scanf(%d,&n);
  for(int i=1;i=n-1;i++){
    int u,v;scanf(%d%d,&u,&v);G[u].push_back(v),G[v].push_back(u);
    ++deg[u],++deg[v];
  }
  if(n==2) return printf(2 2n1 1n),0;
  dfs(1,0);
  mark(1,0,0);
  printf(%d %dn,max(f[1][0],f[1][1]),f[1][0]==f[1][1]min(g[1][0],g[1][1])(f[1][0]f[1][1]g[1][0]g[1][1]));
  for(int i=1;i=n;i++) printf(%d ,mrk[i]deg[i]1);
  return 0;
}
posted @ 2023-07-25 14:19  Zimo_666  阅读(9)  评论(0编辑  收藏  举报