首先处理出选1做当前目录的答案,然后可以直接递推得到选儿子y做当前目录的答案,
f[y]=f[1]−(len[y]+1)∗sz[y]+3∗(n−sz[y])
。复杂度
O(n)
其中sz[y]表示y的子树中的叶子个数,n为总的叶子个数,都可以提前预处理出来。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,len[N],sz[N],dis[N],leaf=0;
ll f[N],ans=0;
vector<int>son[N];
inline void dfs(int x){
for(int i=0;i<son[x].size();++i){
int y=son[x][i];dis[y]=dis[x]+len[y]+1;
dfs(y);sz[x]+=sz[y];
}if(!son[x].size()) sz[x]=1,dis[x]--,f[1]+=dis[x];
}
inline void dfs1(int x){
for(int i=0;i<son[x].size();++i){
int y=son[x][i];if(!son[y].size()) continue;
f[y]=f[x]-(len[y]+1)*sz[y]+3*(leaf-sz[y]);
ans=min(ans,f[y]);dfs1(y);
}
}
int main(){
// freopen("dirtraverse.in","r",stdin);
// freopen("dirtraverse.out","w",stdout);
n=read();
for(int i=1;i<=n;++i){
char s[20];scanf("%s",s+1);
len[i]=strlen(s+1);int m=read();if(!m) ++leaf;
while(m--) son[i].push_back(read());
}dfs(1);ans=f[1];dfs1(1);
printf("%lld\n",ans);
return 0;
}