Codeforces965E Short Code 【启发式合并】【堆】
题目大意:
给出总长度不超过1E+5的不重复字符串集,给每个字符串选一个前缀使得可以区分它。
题目分析:
KAN出的DIV2难度一般不高,想升Ranting的可以试试。
简单的树上启发式合并,建出Trie树,一开始每个字符串用自己表示,每次向上合并的时候选出堆中最大元素变成当前位置,特判一下有end的地方即可。
证明也很简单,我们考虑一个根没被选的子树,若我们要使得这个子树的代价最小,那么我们一定要选择一个位置放到根上来,不难发现选择深度最大的点是会最小的。由于树的子结构的关系,这样向上归纳也是正确的。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int sigma = 26; 5 6 int n,num,len,root; 7 char str[105000]; 8 struct trie{ 9 int end,sz,nxt[30]; 10 }T[105000]; 11 12 int Num(char ch){return ch-'a';} 13 14 void insert(int now,int pla){ 15 if(pla == len) {T[now].sz++;T[now].end=1;return;} 16 int um = Num(str[pla]); 17 if(T[now].nxt[um]){ 18 insert(T[now].nxt[um],pla+1); 19 }else{ 20 num++; T[now].nxt[um] = num; 21 insert(T[now].nxt[um],pla+1); 22 } 23 } 24 25 void dfs(int now){ 26 for(int i=0;i<sigma;i++) 27 if(T[now].nxt[i]) dfs(T[now].nxt[i]),T[now].sz+=T[T[now].nxt[i]].sz; 28 } 29 30 void read(){ 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++){ 33 scanf("%s",str); 34 len = strlen(str); 35 insert(root,0); 36 } 37 dfs(root); 38 } 39 40 int ans = 0; 41 int bel[102000]; 42 priority_queue<int,vector<int>,less<int> > q[102000]; 43 44 int merge(int a,int b){ 45 if(q[a].size()<q[b].size()){ 46 while(!q[a].empty()){ 47 int k = q[a].top();q[a].pop(); 48 q[b].push(k); 49 } 50 return b; 51 }else{ 52 while(!q[b].empty()){ 53 int k = q[b].top();q[b].pop(); 54 q[a].push(k); 55 } 56 return a; 57 } 58 } 59 60 void dfs2(int now,int val){ 61 int flag = false; 62 for(int i=0;i<sigma;i++){ 63 if(T[now].nxt[i]) flag=true,dfs2(T[now].nxt[i],val+1); 64 } 65 if(!flag){bel[now]=++num;q[num].push(val);return;} 66 for(int i=0;i<sigma;i++){ 67 if(T[now].nxt[i]){ 68 if(bel[now]){bel[now]=merge(bel[now],bel[T[now].nxt[i]]);} 69 else bel[now] = bel[T[now].nxt[i]]; 70 } 71 } 72 if(T[now].end){ 73 q[bel[now]].push(val); 74 }else{ 75 q[bel[now]].pop(); 76 q[bel[now]].push(val); 77 } 78 } 79 80 void work(){ 81 num = 0; 82 for(int i=0;i<sigma;i++){ 83 if(!T[root].nxt[i]) continue; 84 dfs2(T[root].nxt[i],1); 85 int hh = bel[T[root].nxt[i]]; 86 while(!q[hh].empty()){ 87 ans += q[hh].top();q[hh].pop(); 88 } 89 } 90 printf("%d",ans); 91 } 92 93 int main(){ 94 read(); 95 work(); 96 return 0; 97 }