您的位置:首页 > 其它

UVA11732 左儿子右兄弟 Trie

2016-10-05 20:30 309 查看
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 <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: