题意:有一棵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 }
原文地址:https://www.cnblogs.com/myx12345/p/9917049.html
时间: 2024-10-08 23:43:46