UVA11732 左儿子右兄弟 Trie

tot[i]记录每个以i为根的树的叶子节点的数目

注意插入的时候要插入‘\0’   为了分辨 前缀和相同的串

对于叶子节点  ans+=tot[u]*(tot[u]-1)/2*2*depth;

即相同的串两两一对的对数 *(2*深度)

对于非叶子节点 统计以其为根节点的串 两两一对的对数

           for(int v=head[u];v;v=next[v]){
                sum+=tot[v]*(tot[u]-tot[v]);//该节点和其他兄弟节点的叶子节点数(串数)
            }
            ans+=sum/2*(2*depth+1);///重复计算 除2

#include 
#include
#include
#include
using namespace std;
const int maxn=4010*1000+10;
typedef long long ll;
struct Trie
{
    int head[maxn];
    int next[maxn];
    int tot[maxn];
    char ch[maxn];
    int sz;
    ll ans;
    void clear() {
        head[0]=next[0]=tot[0]=0;
        ans=0;
        sz=1;
    }
    void insert(char *s) {
        int l=strlen(s),v,u=0;
        tot[0]++;
        for(int i = 0; i <= l; ++i) {
            bool found=0;
            for(v=head[u];v!=0;v=next[v]) {
                if(ch[v]==s[i]) {
                    found=1;
                    break;
                }
            }
            if(!found) {
                v=sz++;
                ch[v]=s[i];
                next[v]=head[u];
                head[u]=v;
                head[v]=0;
                tot[v]=0;
            }
            u=v;
            tot[u]++;
        }
    }
    void dfs(int depth,int u) {
        if(head[u]==0) {
            ans+=tot[u]*(tot[u]-1)/2*2*depth;
        }
        else {
            ll sum=0;
            for(int v=head[u];v;v=next[v]){
                sum+=tot[v]*(tot[u]-tot[v]);
            }
            ans+=sum/2*(2*depth+1);
            for(int v=head[u];v;v=next[v]) {
                dfs(depth+1,v);
            }
        }
    }
    ll count()
    {
        dfs(0,0);
        return ans;
    }
};
Trie trie;
int n;
char c[4010];
int main()
{
    int Kase=0;
    while(~scanf("%d",&n)&&n) {
        trie.clear();
        for(int i = 0; i < n; ++i) {
            scanf("%s",c);
            trie.insert(c);
        }
        printf("Case %d: %lld\n",++Kase,trie.count());
    }
    return 0;
}


你可能感兴趣的:(白书,Trie)