UVA 11732 trie树 + 插入式比较

传送门:UVA 11732

题意

给你n个单词,让他们两两比较,要求他们运用strcmp时,进行比较的次数。
根据题目数据量的范围,肯定不能用简单模拟,然后就想到比较时建Trie树,关键是考虑怎么计数,例如than和that它们比较的次数就是7次,因为他们是在a之后出现不同,就是要记录比较结束的位置,来进行计算即可,那么我们就来一个val数组代表计数器就好了,代表经过该节点的单词个数。

题解思路

第一发写的插入后遍历, T了, 然后改成插入时比较, 不过写搓了, T了好几发
主要是这个要记录比较次数巧一些, 貌似左孩子右兄弟trie树更好过, 不过不会敲。。。
这题主要是trie树的层次问题, 插入时更新比较次数, 省时不过处理有点麻烦

AC code:

    /* adrui's submission Language : C++ Result : Accepted Love : yy Favorite : Dragon Balls Standing in the Hall of Fame */


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<bitset>
#include<map>
#include<cctype>
using namespace std;

#define M(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define ls rt << 1, l, mid
#define rs rt << 1|1, mid + 1, r
#define lowbit(x) (x & (-x))
#define LL long long
#define REP(n) for(int i = 0; i < n; i++)
#define debug 0


const int maxn(4000005);                                                //最大节点数

int N;
int ch[maxn][62];
int val[maxn];
int isend[maxn];

int idx(char p) {                                                       //每个节点分支节点的下标
    if (isalpha(p)) {
        if (islower(p))
            return p - 'a' + 36;
        return p - 'A' + 10;
    }

    return p - '0';
}


struct TrieTree {


    int cnt;
    LL ans;

    TrieTree() {                                                
        cnt = 1;
        ans = 0;
        M(val, 0);
        M(ch, 0);
        M(isend, 0);
    }

    void insert_node(char *s) {                                 //插入时比较
        int len = strlen(s);
        int u = 0;
        for (int i = 0; i < len; ++i) {
            int tmp = idx(s[i]);
            if (!ch[u][tmp]) {                                  //当前分支找不到改点, 累加上一层比较次数
                ans += val[u] * (i << 1 | 1);
                ch[u][tmp] = cnt++;
            }
            else {
                ans += (val[u] - val[ch[u][tmp]]) * (i << 1 | 1);//找到, 也累加不过暂时要排除可继续比较的分支
            }

            ++val[u];                                            //更新该点权值
            u = ch[u][tmp];
        }

        ans += isend[u] * (2 * len + 2);                          //之前的相同单词比较
        ans += (val[u] - isend[u]) * (2 * len + 1);               //到达串尾部, 这个累加同上方原理

        ++val[u];
        ++isend[u];                                              //更新该单词出现个数
    }


};

int main() {
#if debug
    freopen("in.txt", "r", stdin);
#endif //debug

    cin.tie(0);
    cin.sync_with_stdio(false);


    char s[1010];

    int kase = 0;

    while (cin >> N, N) {
        TrieTree root;
        cout << "Case " << ++kase << ": ";

        for (int i = 0; i < N; ++i) {
            cin >> s;
            root.insert_node(s);
        }

        cout << root.ans << endl;
    }
    return 0;
}

总结

  1. 刚开始有RE, 看错数组大小, 懵逼, 毛病改不了啊
  2. 数据结构问题最好尝试全用数组模拟, 这样找bug会容易很多
  3. 多刷题!
    原文作者:Trie树
    原文地址: https://blog.csdn.net/ADjky/article/details/53054736
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞