• 算法竞赛进阶指南——字典树学习笔记


    字典树的插入以及删除操作

    #include <bits/stdc++.h>
    using namespace std;
    #define N 10010
    int tire[N][26];
    int tot = 1;
    bool end[N];//如果为真,那么就意味着这一个点是结尾 
    char buf[N];
    void insert(char *s)
    {
    	int p = 1;
    	int len = strlen(s);
    	for(int i = 0; i < len; i++)
    	{
    		int x = s[i] - 'a';
    		if(tire[p][x] == 0) tire[p][x] = ++tot;
    		p = tire[p][x];
    	}
    	end[p] = true;
    }
    bool search(char * s)
    {
    	int p = 1;
    	int len = strlen(s);
    	for(int i = 0; i < len; i++)
    	{
    		p = tire[p][s[i]-'a'];
    		if(!p) return false;
    	}
    	return end[p];
    }
    int main()
    {
    	int n, m;
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) 
    	{
    		scanf("%s", &buf);
    		insert(buf);
    	}
    	for(int i = 1; i <= m; i++)
    	{
    		scanf("%s", buf);
    		if(search(buf)) printf("yes\n");
    		else printf("no\n");
    	} 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    AcWing142. 前缀统计

    这道题目很显然会想到使用字典树(应为可以使用树来对不同前缀的进行分叉)
    在这里插入图片描述

    代码

    #include <bits/stdc++.h>
    using namespace std;
    #define N 1000020
    int trie[N][26];
    int tot = 1;
    int cnt[N];
    char buf[N];
    void ins(char *s)
    {
        int p = 1;
        cnt[p]++;
        int len = strlen(s);
        for(int i = 0; i < len; i++)
        {
    
            if(trie[p][s[i]-'a'] == 0) trie[p][s[i]-'a'] = ++tot;
            p = trie[p][s[i]-'a'];
        }
        cnt[p] ++;
    }
    int ser(char *s)
    {
        int ans = 0;
        int len = strlen(s);
        int p = 1;
        for(int i = 0; i < len; i++)
        {
            p = trie[p][s[i]-'a'];
            if(!p) break;
            ans += cnt[p];
        }
        return ans;
    }
    int main()
    {
        int n, m;
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
        {
            scanf("%s", buf);
            ins(buf);
        }
        for(int i = 1; i <= m; i++)
        {
            scanf("%s", buf);
            printf("%d\n", ser(buf));
    
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    AcWing\143. 最大异或对

    字典序就是把

    1. 这道题目如果使用俩俩逐个进行比较,显然是不行。

    2. 对于这道题目,我一开始想象,如果随着输入一遍之后直接通过树来得到结果,显然是不行。

      在这里插入图片描述
      对于如图所示的情况,第一层可以选择不相同的,但是第二层不知道是左面是0还是右面是0,这样就需要不断试探。。。。。。
      3. 看了一下数据范围,输入数据,需要 O ( n ) O(n) O(n),其实可以使用 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n的算法。
      枚举每一个值,贪心找到与他异或最大的数字!

    #include <bits/stdc++.h>
    using namespace std;
    #define N 3200000
    #define M 100010
    int trie[N][2];
    int tot = 1;
    int s[M];
    void insert(int x)
    {
        int p = 1;
        for(int i = 31; i >= 0; i--)
        {
            int z = (x >> i) & 1;
            if(trie[p][z] == 0) trie[p][z] = ++tot;
            p = trie[p][z];
        }
    }
    int search(int x)
    {
        int ret = 0;
        int p = 1;
        for(int i = 31; i >= 0; i--)
        {
            int z = ((x>>i) & 1)^1;
            if(trie[p][z] != 0)
            {
                p = trie[p][z];
                ret = (ret << 1) + 1;
            }
            else
            {
                z = !z;
                p = trie[p][z];
                ret = (ret << 1);
            }
        }
        return ret;
    }
    int main()
    {
        int ans = 0;
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
            int in;
            scanf("%d", &in);
            s[i] = in;
            insert(in);
        }
        for(int i = 1; i <= n; i++)
        {
            int ret = search(s[i]);
            ans = max(ret, ans);
        }
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    ACWing\144. 最长异或值路径

    对于这道题目,一是摸不着头脑。

    因为涉及到树,并不是任意两个点之间都可以进行异或。。。

    但是:

    树是一种特殊的图,感觉对于树,可以任意拎出来一个节点,当做是根节点,这时候,不是在同一个分支的两个点之间的路径必定经过父亲节点
    eg
    在这里插入图片描述
    注意:由于具有相同的值的异或等于0,并且0异或其他的数字相当于没有异或。
    在这里插入图片描述
    只要求出根节点到每一个节点的异或,然后就好了。

    代码

    
    
    #include <bits/stdc++.h>
    using namespace std;
    #define N 1000200//竟然是数组开小了
    /*树开始*/
    int head[N], nxt[N], vis[N], edge[N], arc[N];
    int tot = 1;//可以进行对偶(已经知道一条边,那么这条边的id ^ 1就是与他方向相反的边)
    /*树结束*/
    /*字典树开始*/
    int trie[N*32][2];
    int cnt = 1;//1表示为根节点
    /*字典树结束*/
    int s[N];//字典树里面的所有元素
    int s_cnt = 0;
    void insert(int x)
    {
        s[++s_cnt] = x;
        int p = 1;//不初始化害死人
        for(int i = 31; i >= 0; i--)
        {
            int z = (x>>i) & 1;
            if(trie[p][z]==0) trie[p][z] = ++cnt;
            p = trie[p][z];
        }
    }
    void add(int u, int v, int w)
    {
        arc[++tot] = v;
        edge[tot] = w;
        nxt[tot] = head[u];
        head[u] = tot;
    }
    void DFS(int T, int sum)
    {
        if(vis[T]) return;
        vis[T] = 1;
        for(int i = head[T]; i; i = nxt[i])
        {
            int to = arc[i];
            if(vis[to]) continue;
            insert(sum ^ edge[i]);
            DFS(to, sum ^ edge[i]);
        }
    }
    int search(int x)
    {
        int ret = 0;
        int p = 1;
        for(int i = 31; i >= 0; i--)
        {
            int z = ((x >> i) & 1)^1;
            if(trie[p][z] != 0)
            {
                ret = (ret << 1) + 1;
                p = trie[p][z];
            }
            else
            {
                ret = ret << 1;
                p = trie[p][1^z];
            }
        }
        return ret;
    }
    int main()
    {
        int ans = 0;
        int n;
        cin >> n;
        for(int i = 1; i <= n-1; i++)
        {   
            int u, v, w;
            u++;//注意:我这里点是从1开始的
            v++;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        DFS(1, 0);
        insert(0);//注意:深度优先并不会添加从root到root的异或值
        for(int i = 1; i <= n; i++)
        {
            int ret = search(s[i]);
            ans = max(ans, ret);
        }
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
  • 相关阅读:
    浅谈微服务-SpringCloud以及框架发展史
    【Axios封装示例Vue2】
    Ubuntu下qt编译问题
    windows系统完全卸载并重装Node(亲测可用)
    C++中的有参构造函数
    javascript设计模式单例
    pytorch中torch.where()使用方法
    ClickHouse Senior Course Ⅱ
    vr虚拟现实游戏世界介绍|数字文化展览|VR元宇宙文旅
    ffmpeg推流+NGINX(RTMP)+VLC-QT拉流(Win7)
  • 原文地址:https://blog.csdn.net/xjsc01/article/details/125509486