卧薪尝胆,厚积薄发。
USACO2018FEB GOLD Directory Traversal
Date: Wed Sep 19 20:27:29 CST 2018 In Category: NoCategory

Description:

给一个文件系统,选择一个文件夹,使得从该文件夹出发对所有文件相对路径的长度之和最小。
$1\le n \le 100000$

Solution:

比较容易的二次扫描与换根。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n;
int cnt = 0;
#define MAXN 100010
char s[MAXN][20];
int len[MAXN];
struct edge
{
int to,nxt;
}e[MAXN];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
bool tag[MAXN];
int siz[MAXN];
long long f[MAXN];
void dfs1(int k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(tag[e[i].to])
{
++siz[k];
f[k] += len[e[i].to];
}
else
{
dfs1(e[i].to);
siz[k] += siz[e[i].to];
f[k] += siz[e[i].to] * (1 + len[e[i].to]) + f[e[i].to];
}
}
return;
}
void dfs2(int k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
f[e[i].to] = f[k] - siz[e[i].to] * (1 + len[e[i].to]) + (cnt - siz[e[i].to]) * 3;
dfs2(e[i].to);
}
return;
}
int main()
{
scanf("%d",&n);
int a,b;
for(int i = 1;i <= n;++i)
{
scanf("%s",s[i] + 1);
scanf("%d",&a);
len[i] = strlen(s[i] + 1);
if(a == 0)
{
tag[i] = true;
siz[i] = 1;
++cnt;
}
for(int j = 1;j <= a;++j)
{
scanf("%d",&b);
add(i,b);
}
}
dfs1(1);
dfs2(1);
long long ans = 0x3f3f3f3f3f3f3f3f;
for(int i = 1;i <= n;++i)
{
ans = min(ans,f[i]);
}
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡