CF-778 C.Peterson Polyglot(Trie合并)
题意
给一个 T r i e Trie Trie树,问删除那一层剩下的节点数最少,输出最小数量的节点数和删除的最小层数
删除节点之后,子节点相同的点会合并在一起
思路
枚举删除每个节点,计算它对这一层的贡献
删除的实现是通过合并节点来实现的
首先新建节点 n o w now now表示合并之后的节点,此时需要删除节点 x x x即 m e r g e ( n o w , x ) merge(now,x) merge(now,x)
m e r g e merge merge的流程是:新建 t m p tmp tmp节点表示合并之后的节点并返回给 n o w now now,然后从’ a a a’ - ' z z z'合并 n o w now now和 x x x,如果 n o w now now和 x x x同时有边,表示子节点可以合并在一起,所以递归下去
最后判断最小值
#include <bits/stdc++.h>
const int maxn = 4e5 + 5;
using namespace std;
int nex[maxn][26], ans[maxn];
int cnt, n;
int merge(int x, int y) {
// printf("%d %d\n", x, y);
if (x == 0 || y == 0) return x|y;
int tmp = ++cnt;
for (int i = 0; i < 26; ++i) nex[tmp][i] = merge(nex[x][i], nex[y][i]);
return tmp;
}
void dfs(int u, int level) {
int now = n + 1;
cnt = now;
for (int i = 0; i < 26; ++i) {
if (nex[u][i]) now = merge(now, nex[u][i]);
}
// printf("u %d, level %d, cnt %d\n", u, level, cnt);
ans[level] += cnt - n - 1;
for (int i = 0; i < 26; ++i) {
if (nex[u][i]) dfs(nex[u][i], level+1);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; ++i) {
int u, v;
char c;
scanf("%d %d %c", &u, &v, &c);
nex[u][c - 'a'] = v;
}
dfs(1, 1);
int sz = 0, p;
for (int i = 1; i <= n; ++i) {
if (sz < ans[i]) {
sz = ans[i];
p = i;
}
}
printf("%d\n%d\n", n-sz, p);
return 0;
}