【CF778C】Peterson Polyglot(Trie树,启发式合并)

题意:有一棵n个结点的只由小写字母组成的Trie树,给定它的具体形态,问删除哪一层后剩下Trie树的结点数最少

n<=3e5

思路:先建出原Trie树,对于每一层的每一个结点计算删除后对答案的贡献,这一部分使用启发式合并

官方题解证明了时间复杂度是一个log的

http://codeforces.com/blog/entry/50724

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 typedef long long ll;
 6 using namespace std;
 7 #define N 310000
 8 
 9 int map[N][27],head[N],vet[N<<1],nxt[N<<1],size[N],dep[N],ans[N],flag[N],
10     n,cnt,tot;
11      
12 char len[N<<1],ch[10];
13 
14 void add(int a,int b,char c)
15 {
16     nxt[++tot]=head[a];
17     vet[tot]=b;
18     len[tot]=c;
19     head[a]=tot;
20 }
21 
22 int merge(int x,int y)
23 {
24     if(!x||!y) return x+y;
25     int t=++cnt; 
26     size[t]=1;
27     for(int i=1;i<=26;i++)
28     {
29         map[t][i]=merge(map[x][i],map[y][i]);
30         size[t]+=size[map[t][i]];
31     }
32     return t;
33 }
34 
35 void dfs(int u)
36 {
37     size[u]=flag[u]=1;
38     int e=head[u];
39     while(e)
40     {
41         int v=vet[e];
42         if(!flag[v])
43         {
44             dep[v]=dep[u]+1;
45             map[u][len[e]-'a'+1]=v;
46             dfs(v);
47             size[u]+=size[v];
48         }
49         e=nxt[e];
50     }
51     ans[dep[u]]+=size[u]; 
52     cnt=n;
53     int t=0;
54     for(int i=1;i<=26;i++) t=merge(t,map[u][i]);
55     ans[dep[u]]-=max(size[t],1);
56 }
57 
58 int main()
59 {
60     scanf("%d",&n);
61     for(int i=1;i<=n-1;i++)
62     {
63         int x,y;
64         scanf("%d%d%s",&x,&y,ch);
65         add(x,y,ch[0]);
66         add(y,x,ch[0]);
67     }
68     memset(flag,0,sizeof(flag));
69     dfs(1); 
70     int k=0;
71     for(int i=0;i<=n-1;i++) 
72      if(ans[k]<ans[i]) k=i;
73     printf("%d\n",n-ans[k]);
74     printf("%d\n",k+1);
75     return 0;
76 }

猜你喜欢

转载自www.cnblogs.com/myx12345/p/9917049.html