多叉树转二叉树
问题描述:
一棵有根树,规定根节点深度为 0 ,其他节点深度等于父亲的深度 +1 。 有一棵多叉树,你需要把它按照“左儿子右兄弟”的规则转化为二叉树。 设节点 x 转化前后深度分别为 d1[x],d2[x] , 则转化的代价为∑∣d1[x]−d2[x]∣ 请你分别求出最小代价和最大代价。
分析:
考察树形dp,贪心。
$f[x]$表示以$x$为根的子树转换后的最大代价。
f[x]=sigma(f[v])+sz[v1]*0+sz[v2]*1+sz[v3]*2....
$sz[x]$表示$x$的子树中的节点个数。
当$sz[x]$从小到大排好序,便可贪心求出答案。
#include<bits/stdc++.h> using namespace std; #define re register int #define LL long long static char buf[1<<20], *p1=buf, *p2=buf; #define getchar() p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<20, stdin), p1==p2)?EOF:*p1++ inline int read() { int x=0, flag=0; char c=getchar(); while(c<'0'||c>'9') { if(c=='-')flag=1; c=getchar(); } while('0'<=c&&c<='9')x=(x<<1)+(x<<3)+c-48,c=getchar(); return flag?-x:x; } const int N=1e6+5; int sz[N]; LL f[N], g[N]; int tt, las[N], ed[N<<1], nt[N<<1]; void add(int x, int y){ ed[++tt]=y;nt[tt]=las[x];las[x]=tt; } int tmp[N]; void DFS(int x, int fa) { int son = 0; sz[x] = 1; for(re i=las[x];i;i=nt[i]) { int v=ed[i]; if(v != fa) { DFS(v, x); sz[x] += sz[v]; f[x] += f[v]; g[x] += g[v]; } } for(re i=las[x];i;i=nt[i]) { int v=ed[i]; if(v != fa) tmp[++son]=sz[v]; } sort(tmp+1, tmp+1+son); for(re i=1;i<=son;++i) { f[x]+=1ll*(i-1)*tmp[i]; g[x]+=1ll*(son-i)*tmp[i]; } } int main() { int n=read(); for(re i=1;i<n;++i) { int x=read(), y=read(); add(x, y); add(y, x); } DFS(1, 0); printf("%lld %lld", g[1], f[1]); return 0; }