UVA 11732题解

// 字典树的左儿子右兄弟法
// 相同长度则为 strlen(str)*2 + 2 不同则为 公共前缀 + 1
#include<bits/stdc++.h>
#define rep(i, n) for(int i=0;i!=n;++i)
#define per(i, n) for(int i=n-1;i>=0;--i)
#define Rep(i, sta, n) for(int i=sta;i!=n;++i)
#define rep1(i, n) for(int i=1;i<=n;++i)
#define per1(i, n) for(int i=n;i>=1;--i)
#define Rep1(i, sta, n) for(int i=sta;i<=n;++i)
#define L rt<<1
#define R rt<<1|1
#define inf (0x3f3f3f3f)
#define llinf (1e18)
#define ALL(A) A.begin(),A.end()
#define SIZE(A) ((int)A.size())
#define MOD (1e9 + 7)
#define PII pair<int,int>
typedef long long i64;
using namespace std;
const int maxnode = 4e6 + 32;
struct Trie{
    int son[maxnode],bro[maxnode],num[maxnode];//num -->对应的为根的叶子节点个数
    char ch[maxnode];
    i64 ans;    int total;
    void init(){
        total = 1;
        son[0] = bro[0] = num[0] = 0;//根节点
        ans = 0;
    }
    void insert(string &str){
        int len = str.length();
        int pos,cur = 0;
        for(int i=0;i<=len;++i){// ''表示叶子节点
            for(pos = son[cur];pos;pos = bro[pos]){
                if(ch[pos] == str[i])
                    break;
            }
            if(!pos){
                pos = total++;
                ch[pos] = str[i];
                bro[pos] = son[cur];
                son[cur] = pos;
                son[pos] = num[pos] = 0;//新节点
            }
            ans += (num[cur]-num[pos]) * (2*i+1);//前缀长度为i
            if(i == len){
                ans += num[pos] * (2*i+2);
                ++num[pos];//相同的前缀
            }
            num[cur]++;
            cur = pos;
        }               
    }    
}tree;
int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n,kase = 0;  string temp;
    while(cin >> n && n){
        tree.init();
        for(int i=0;i!=n;++i){
            cin >> temp;
            tree.insert(temp); 
        }
        cout << "Case "<< ++kase << ": " << tree.ans << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/newstartCY/p/13618583.html