CF965E Short Code(Trie+启发式合并)
启发式合并是自底向上的,将小的集合合并到大的集合上的一种方法,从直觉上来说这样比较优,事实上也证明了这一点。
这题的贪心想法是,如果我当前的点是空的,那么我把子树中最深的点移到这,这样是最优的。那么合并子树集合信息来往上做就是采用启发式合并
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pll; const int N=5e5+10; const int inf=0x3f3f3f3f; const int mod=772002; int n; int tr[N][27],depth[N]; int pos[N]; int idx,rt; ll ans; priority_queue<int> a[N]; void insert(string s){ int i; int p=rt; for(i=0;i<(int)s.size();i++){ int sign=s[i]-'a'; if(!tr[p][sign]){ tr[p][sign]=++idx; depth[idx]=depth[p]+1; } p=tr[p][sign]; } pos[p]=1; } void get(int x,int y){ if(a[x].size()<a[y].size()){ a[x].swap(a[y]); } while(a[y].size()){ a[x].push(a[y].top()); a[y].pop(); } } void dfs(int u){ int i; for(i=0;i<26;i++){ if(tr[u][i]) dfs(tr[u][i]); } for(i=0;i<26;i++){ if(tr[u][i]) get(u,tr[u][i]); } if(!u) return ; if(pos[u]){ ans+=depth[u]; a[u].push(depth[u]); } else{ ans-=a[u].top(); ans+=depth[u]; a[u].pop(); a[u].push(depth[u]); } } int main(){ ios::sync_with_stdio(false); cin>>n; int i; for(i=1;i<=n;i++){ string s; cin>>s; insert(s); } dfs(0); cout<<ans<<endl; return 0; }
没有人不辛苦,只有人不喊疼