一开始不知道这种一维建树方法。
每次一层用一个链指向下一层最左边的结点,之后每一层用一个链表串联所有的结点,这样就建树成功了。
14328524 | 11732 | strcmp() Anyone? | Accepted | C++ | 0.826 | 2014-10-09 13:13:14 |
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> pill;
const int nodemaxn = 4000 * 1000 + 100;
struct Trie{
int head[nodemaxn]; //左儿子链
int next[nodemaxn]; //右兄弟链
int ch[nodemaxn]; //这个结点代表的字符
LL tot[nodemaxn]; //有几个单词经过了这个结点
int sz; //结点个数
LL ret; //比较的次数
void clear(){
head[0] = 0; next[0] = 0; tot[0] = 0; sz = 1; ret = 0;
}
void insert(char *str){
int L = strlen(str);
int u = 0,v,found;
tot[0]++;
for(int i = 0; i <= L; i ++){
found = 0;
for(v = head[u]; v != 0 ; v = next[v]){ //到下一层去找
if(ch[v] == str[i]){
found = 1;
break;
}
}
if(!found){ //如果没有找到
v = sz ++;
tot[v] = 0;
ch[v] = str[i];
next[v] = head[u];
head[u] = v;
head[v] = 0;
}
u = v;
tot[u] ++;
}
}
void dfs(int u,int depth){
if(head[u] == 0){
ret += tot[u] * (tot[u] - 1) * depth;
}
else{
LL sum = 0;
for(int v = head[u] ; v != 0; v = next[v])
sum += tot[v] * (tot[u] - tot[v]);
ret += sum / 2 * (2 * depth + 1);
for(int v = head[u] ; v != 0; v = next[v])
dfs(v,depth + 1);
}
}
}trie;
const int maxn = 4000 + 10;
int main(){
int n,Case = 1;
while(scanf("%d",&n) && n){
trie.clear();
for(int i = 0; i < n; i++){
char str[maxn];
scanf("%s",str);
trie.insert(str);
}
trie.dfs(0,0);
printf("Case %d: %lld\n",Case++,trie.ret);
}
}