• 字典树&01字典树算法笔记


    1】学习了字典树之后,觉得它很明显的就是用空间来换时间,空间复杂度特别大,比如字典数单单存26个小写字母,那么每个节点的孩子节点都有26个孩子节点,字典树中的每一层都保留着不同单词的相同字母。

    2】01字典树主要用于解决求异或最值的问题

    #include<cstdio>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<cctype>
    #include<stack>
    #include<sstream>
    #include<list>
    #include<assert.h>
    #include<bitset>
    #include<numeric>
    #define debug() puts("++++")
    #define gcd(a,b) __gcd(a,b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a,b,sizeof(a))
    #define sz size()
    #define be begin()
    #define mp make_pair
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define lowbit(x) -x&x
    #define all 1,n,1
    #define rep(i,x,n) for(int i=(x); i<=(n); i++)
    #define in freopen("in.in","r",stdin)
    #define out freopen("out.out","w",stdout)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> P;
    const ULL base = 100000007;//33951943
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e18;
    const int maxn = 1e5+20;
    const int maxm = 1e5 + 10;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int dx[] = {-1,1,0,0,1,1,-1,-1};
    const int dy[] = {0,0,1,-1,1,-1,1,-1};
    int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    int ch[32*maxn][2]; //边的值
    LL val[32*maxn];    //点的值
    int id;             //树中当前结点个数
    void init()
    {
        ms(ch[0],0);
        id=1;
    }
    void Insert(LL x) //在字典树中插入x
    {
        int u=0;
        for(int i=32;i>=0;i--)
        {
            //和一般的字典树的操作相同将x的二进制插入字典树中
            int c=((x>>i)&1); 
            if(!ch[u][c]) //如果结点未被访问过
            {
                ms(ch[id],0); //将当前结点的边值初始化
                val[id]=0;    //结点值为0,表示到此不是一个数
                ch[u][c]=id++; //边指向的节点编号
            }
            u=ch[u][c]; //下一结点
        }
        val[u]=x; //最后的结点插入val,结点值为x,即到此是一个数
    }
    LL Query(LL x) //在字典树中查找和x异或的最大的元素并返回值
    {
        int u=0;
        for(int i=32;i>=0;i--)
        {
            int c=(x>>i)&1;
            if(ch[u][c^1]) //利用贪心,优先寻找和当前位不同的数
                u=ch[u][c^1];
            else
                u=ch[u][c];
        }
        return val[u]; //返回结果
    }
    int main()
    {
        int n,m,t,ca=0;
        LL x;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            init();
            for(int i=0;i<n;i++)
            {
                scanf("%lld",&x);
                Insert(x);
            }
            printf("Case #%d:
    ",++ca);
            while(m--)
            {
                scanf("%lld",&x);
                printf("%lld
    ",Query(x));
            }
        }
        return 0;
    }
    /*
    【题意】在一组数中找跟某个数异或结果最大的数。
    
    【类型】01字典树
    
    【分析】直接套用模板,将数组中的数插入到 01字典树,对每一个数查询即可。
    
    【时间复杂度&&优化】
    
    【trick】
    
    【数据】
    */
    HDU 4185

    1. 01字典树是一棵最多 32层的二叉树,其每个节点的两条边分别表示二进制的某一位的值为 0 还是为 1. 将某个路径上边的值连起来就得到一个二进制串。

    2.节点个数为 1 的层(最高层)节点的边对应着二进制串的最高位。

    3.以上代码中,ch[i] 表示一个节点,ch[i][0] 和 ch[i][1] 表示节点的两条边指向的节点,val[i] 表示节点的值。

    4.每个节点主要有 4个属性:节点值、节点编号、两条边指向的下一节点的编号。

    5.节点值 val为 0时表示到当前节点为止不能形成一个数,否则 val[i]=数值。

    6.节点编号在程序运行时生成,无规律。

    7.可通过贪心的策略来寻找与 x异或结果最大的数,即优先找和 x二进制的未处理的最高位值不同的边对应的点,这样保证结果最大。

    例题:

    一、HDU 4825

    传送门:HDU 4825

    题目大意:在一组数中找跟某个数异或结果最大的数。

    题解:直接套用模板,将数组中的数插入到 01字典树,对每一个数查询即可。

    二、HDU 5536

    传送门:HDU 5536

    题目大意:在一个数组中找出 (s[i]+s[j])^s[k] 最大的值,其中 i、j、k 各不相同。

    题解:HDU 5536 题解

    三、BZOJ 4260

    传送门:BZOJ 4260

    题目大意:给你 n 个数,让你求两个不相交的区间元素异或后的和的最大值。

    题解:BZOJ 4260 题解

    四、POJ 3764

    传送门:POJ 3764

    题目大意:在树上找一段路径(连续)使得边权相异或的结果最大。

    题解:POJ 3764 题解

  • 相关阅读:
    动态规划精讲(一)LC最长公共子序列
    0-1背包
    折线分割平面
    母牛的故事
    数塔
    70. 爬楼梯
    文件修改的两种方式
    文件处理练习
    文件处理
    购物车理解
  • 原文地址:https://www.cnblogs.com/Roni-i/p/9449592.html
Copyright © 2020-2023  润新知