zoukankan      html  css  js  c++  java
  • 字典树及其应用

    浅析字典树

    字典树是一种比较特殊的树,边上有边权(至少我是怎么理解的)。又名“Trie”树。

    大概长这样:

    1hwGtI.png

    (插入了cap,cat,csp,co,code)

    边上是字符集,点上是点的编号,涂成蓝色的代表是单词的结尾。

    字符集可以是a-z0-9true和false等等。

    字典树有效的组织了单词的关系,节省了时间和空间。

    插入单词

    void insert(char *s) {
        int p = 1, len = strlen(s);
        for (int i = 0; i < len; ++i) {
            bool now = s[i] - 'a';
            if (trie[p][now] == 0) trie[p][now] = ++m;
            p = trie[p][now];
        }
        isend[p] = true;
    }
    

    这里trie[x][c]表示从节点xc这条边能达到节点trie[x][c]

    其中,m为节点总数计数,要在插入前赋初始值为 (1)

    这里isend用于标记是否是结尾,有时还需要记录次数。

    查询

    每道题都有他查询的内容,需要因地制宜的写查询函数。

    查询前缀是否出现:

    bool query(char *s) { // 此代码没有编译运行测试过,仅供思路参考,不建议直接复制。
        int p = 1, len = strlen(s);
        for (int i = 0; i < len; ++i) {
            bool now = s[i] - 'a';
            if (trie[p][now] == 0) return false;
            p = trie[p][now];
        }
        return true;
    }
    

    查询出现次数(注意配套修改insert函数):

    int query(char *s) { // 此代码没有编译运行测试过,仅供思路参考,不建议直接复制。
        int p = 1, len = strlen(s);
        for (int i = 0; i < len; ++i) {
            bool now = s[i] - 'a';
            if (trie[p][now] == 0) return 0;
            p = trie[p][now];
        }
        return isend[p];
    }
    

    应用

    本文主要谈应用字典树解题,如果上面的讲解不明白,可以自行Baidu一下qwq。

    例题一 于是他错误的点名开始了

    查看原题-洛谷P2580

    这题是字典树最基本的运用,查询存在性和重复性。

    把所有化学生的姓名插入字典树,再在每次教练点名时,查询。

    例题二 The XOR Largest Pair

    查看原题-LibreOJ#10050

    这题看似和字典树没啥关系,也找不到可以插入的字符串。

    最容易想到的做法就是暴力,两两枚举xor,时间复杂度 (O(n^2))

    其实这里可以把每个数的二进制值插入字典树中,

    枚举每个数,在字典树中查询与它尽量二进制按位尽量相反的树。

    code:

    void insert(int x) {
        int p = 1;
        for (int i = 30; i >= 0; --i) {
            bool now = (x & (1 << i));
            if (trie[p][now] == 0) trie[p][now] = ++m;
            p = trie[p][now];
        }
        isend[p] = true;
    }
    
    int lookup(int x) {
        int res = 0;
        int p = 1;
        for (int i = 30; i >= 0; --i) {
            bool now = (x & (1 << i));
            now = !now;
            if (trie[p][now]) { // 成功匹配,此位相反
                res |= (1 << i);
                p = trie[p][now];
            } else { // 匹配失败,这一位只能相等
                p = trie[p][!now];
            }
        }
        return res;
    }
    

    例题三 最长XOR序列

    查看题目-暂无题目qwq

    描述:还是给你一个序列,要求这个序列的某个子序列的异或和最大,求这个最大值。

    (注:子序列是连续的,子串才是不连续的。

    异或和是指连续异或的值,如4,7,10的异或和是4 xor 7 xor 10

    这里要用到异或的几个性质:

    1. (a operatorname{xor} b operatorname{xor} c=(a operatorname{xor} b)operatorname{xor} c=aoperatorname{xor}(boperatorname{xor}c))

    2. (a operatorname{xor} a=0)

    3. (aoperatorname{xor}0=a)

  • 相关阅读:
    sqli-libs(3)
    python学习之路(18)
    BZOJ3534:[SDOI2014]重建——题解
    洛谷省选斗兽场全通关祭~以及之后的打算!
    BZOJ4596:[SHOI2016]黑暗前的幻想乡——题解
    BZOJ2732:[HNOI2012]射箭——题解
    BZOJ1486:[HNOI2009]最小圈——题解
    BZOJ4552:[HEOI2016/TJOI2016]排序——题解
    BZOJ2830 & 洛谷3830:[SHOI2012]随机树——题解
    BZOJ4889 & 洛谷3759:[TJOI2017]不勤劳的图书管理员——题解
  • 原文地址:https://www.cnblogs.com/szdytom/p/trie_tree.html
Copyright © 2011-2022 走看看