CodeForces - 778C: Peterson Polyglot (啟發式合併trie樹)
Peterson loves to learn new languages, but his favorite hobby is making new ones. Language is a set of words, and word is a sequence of lowercase Latin letters.
Peterson makes new language every morning. It is difficult task to store the whole language, so Peterson have invented new data structure for storing his languages which is called broom. Broom is rooted tree with edges marked with letters. Initially broom is represented by the only vertex — the root of the broom. When Peterson wants to add new word to the language he stands at the root and processes the letters of new word one by one. Consider that Peterson stands at the vertex u
In the evening after working day Peterson can't understand the language he made this morning. It is too difficult for bored Peterson and he tries to make it simpler. Simplification of the language is the process of erasing some letters from some words of this language. Formally, Peterson takes some positive integer p
Peterson is pretty annoyed with this task so he asks you for help. Write a program to find the smallest possible size of the broom and integer p.
Input
The first line of input contains integer n (2 ≤ n ≤ 3·105) — the size of the broom.
Next n - 1 lines describe the broom: i-th of them contains integers ui, vi and letter xi — describing the edge from ui to vi marked with letter xi.
Vertices are numbered from 1 to n. All xi are lowercase latin letters. Vertex 1 is the root of the broom.
Edges describe correct broom which is made from Peterson's language.
OutputThe first line of output should contain the minimum possible size of the broom after its simplification. The second line of output should contain integer p to choose. If there are several suitable p values, print the smallest one.
Examples Input5Output
1 2 c
2 3 a
3 4 t
2 5 t
3Input
2
16Output
1 2 o
2 3 f
1 4 p
4 5 i
5 6 e
6 7 c
7 8 e
4 9 r
9 10 e
10 11 t
11 12 t
12 13 y
10 14 f
14 15 i
15 16 x
12
2
題意:給定一些單詞的trie樹,現在你可以刪去其中一層(即原有的單詞的某一位),使得新的trie樹最小(即節點數最少)。
思路:我們需要列舉每一層,對於每一層的這些點,需要把它們各自的子樹合併成新的trie樹。 菜雞我一直在想dp去做,維護LCP什麼的,沒想到就是合併樹來做,啟發式可以做到NlogN? (雖然每次用小的加到大的裡面去,但是每個節點都要做一遍合併,我直觀上覺得是兩個log。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1000010; int ch[maxn][26],cnt,a[maxn],N; int merge(int u,int v) { if(!u||!v) return u|v; int now=++cnt; rep(i,0,25) ch[now][i]=merge(ch[u][i],ch[v][i]); return now; } void dfs(int u,int d) { int now=N+1; cnt=N+1; rep(i,0,25) if(ch[u][i]) now=merge(now,ch[u][i]); a[d]+=cnt-N-1; rep(i,0,25) if(ch[u][i]) dfs(ch[u][i],d+1); } int main() { int u,v; char c[3]; scanf("%d",&N); rep(i,1,N-1){ scanf("%d%d%s",&u,&v,c+1); ch[u][c[1]-'a']=v; } dfs(1,1); int ans=0,p=0; rep(i,1,N) if(a[i]>ans) ans=a[i],p=i; printf("%d\n%d\n",N-ans,p); return 0; }