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;
}
View Code

 

posted @ 2020-09-02 11:00  朝暮不思  阅读(226)  评论(2编辑  收藏  举报