UVA11732(左兄弟右儿子的Trie/Trie)

本文介绍了一种使用裸Trie树解决特定问题的方法。通过两个不同实现方式展示了如何插入字符串并计算特定值,涉及左兄弟右儿子结构及内存管理等细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

裸Trie也能过,卡一下内存

#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 20071027
const int maxn = 4000000+5;
using namespace std;
char s[1005];
int n;
LL ans;
struct Trie{
    int ch[maxn][64];
    int val[maxn];
    int sum[maxn][64];
    int sz;
    Trie(){ memset(ch[0], 0, sizeof(ch[0])); sz = 1;}
    int idx(char ch) {
        if('a' <= ch && ch <= 'z')
            return ch - 'a';
        else if('A' <= ch && ch <= 'Z')
            return ch - 'A' + 26;
        else if('0' <= ch && ch <= '9')
            return ch - '0' + 52;
        return ch - '\0' + 62;
    }
    void init(){
        memset(ch[0], 0, sizeof(ch[0]));
        memset(val, 0, sizeof(val));//总的节点数
        memset(sum, 0, sizeof(sum));//当前这种的节点数
        sz = 1;
    }
    void insert(char *s){
        int u = 0, n = (int)strlen(s);
        for(int i=0; i<=n; i++){
            int c = idx(s[i]);
            if(!ch[u][c]){
                memset(ch[sz], 0, sizeof(ch[sz]));
                ch[u][c] = sz++;
            }
            if(i == n){
                ans += 2*(i+1)*sum[u][c];
            }
            ans += 2*i*(val[u]-sum[u][c]) + val[u]-sum[u][c];
            val[u]++;
            sum[u][c]++;
            u = ch[u][c];
        }
    }
}tree;
int main(){
    int kases = 1;
    while(scanf("%d",&n) == 1 && n){
        ans = 0;
        tree.init();
        for(int i=0; i<n; i++){
            scanf("%s",s);
            tree.insert(s);
            //cout << ans << endl;
        }
        printf("Case %d: %lld\n",kases++,ans);
    }
}

左兄弟右儿子没有注释光看代码看的我头疼。。

#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 20071027
const int maxn = 4000 * 1000 + 5;
using namespace std;
char s[1005];
int n;
LL ans;
struct Trie{
    int son[maxn];
    int bro[maxn];
    int val[maxn];
    char ch[maxn];
    int sz;
    Trie(){sz = 1; ch[0] = 0; val[0] = bro[0] = son[0] = 0;}
    void init(){sz = 1; ch[0] = 0;val[0] = bro[0] = son[0] = 0;}
    void insert(char *s){
        int n = (int)strlen(s), u = 0, j;
        for(int i=0; i<=n; i++){
            for(j=son[u]; j; j=bro[j]){//从儿子开始遍历
                if(ch[j] == s[i]) break;
            }
            if(!j){
                j = sz++;//构造新的节点
                ch[j] = s[i];//将该节点字符赋值
                bro[j] = son[u];//将上一个儿子作为该节点的兄弟
                son[j] = val[j] = 0;//因为是新开的节点,所以儿子和个数都是0
                son[u] = j;//原本儿子变为兄弟,新儿子即为j
            }
            ans += (val[u]-val[j])*(2*i+1);//val[u] - val[j]是兄弟的总数
            if(n == i){//如果遍历到最后了即终止符号
                ans += val[j]*(2*i+2);//避免相同字符串
                val[j]++;//因为不会再往下了所以当前位置需要+1,否则会在下一层+1
            }
            val[u]++;//每层有多少个节点
            u = j;
        }
    }
}tree;
int main(){
    int kases = 1;
    while(scanf("%d",&n) == 1 && n){
        ans = 0;
        tree.init();
        for(int i=0; i<n; i++){
            scanf("%s",s);
            tree.insert(s);
        }
        printf("Case %d: %lld\n",kases++,ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值