算法进阶指南-基本数据结构-Trie

1.前缀统计
题目链接
在这里插入图片描述
题解:对n个字符串建立trie,然后对于每一个询问都由浅到深度变量trie即可,线性的复杂度

代码:

#include<iostream>

using namespace std;
const int N=1000010,M=500000;
int n,m;
int son[M][26],cnt[N],idx;
char str[N];

void insert()//建立trie
{
    
    
    int p=0;
    for(int i=0;str[i];i++)
    {
    
    
        int &s=son[p][str[i]-'a'];
        if(!s) s=++idx;//如果该节点不存在,就要建立该节点
        p=s;

    }
    cnt[p]++;//统计p号节点结尾单词的个数

}

int query()//查询
{
    
    


    int p=0,res=0;
    for(int i=0;str[i];i++)
    {
    
    
        int &s=son[p][str[i]-'a'];
        if(!s)break;//已经找到末尾
        p=s;
        res+=cnt[p];
    }
    return res;

}
int main()
{
    
    
    cin>>n>>m;
    while (n--)
    {
    
    
        scanf("%s",str);
        insert();
    }
    while (m--)
    {
    
    
        scanf("%s",str);
        printf("%d\n",query());
    }
    
    


}

2.The XOR Largest Pair

题目链接

在这里插入图片描述
思路:
根据二进制,将每个数都加入trie中,然后遍历遍历每一个数,同时遍历trie,使其尽可能每一位都不同

代码:

#include <iostream>
#include <math.h>
using namespace std;
const int N = 100010, M = 3100010;
int n;
int son[M][2], idx;
int a[N];
void insert(int x)//插入
{
    
    
    int p = 0;
    for (int i = 30; ~i; i--)
    {
    
    

        int &s = son[p][x >> i & 1];
        if (!s)
            s=++idx;
        p = s;
    }
}
int query(int x)
{
    
    
    int res = 0, p = 0;
    for (int i = 30; ~i; i--)
    {
    
    
        int s = x >> i & 1;
        if (son[p][!s])//与x第i位不同的数存在
        {
    
    
            res += 1 << i;
            p = son[p][!s];
        }
        else不存在
        {
    
    
            p = son[p][s];
        }
    }
    return res;
}

int main()
{
    
    
    cin >> n;
    int res=0;
    for (int i = 1; i <= n; i++)
    {
    
    
        cin >> a[i];
        insert(a[i]);
    }
    for (int i = 1; i <= n; i++)
        res = max(res, query(a[i]));

    cout << res << endl;
}

3.The xor-longest Path
题目链接
在这里插入图片描述
题目大意:给一棵树,数上每个点都有一个编号,每条边都有对应的权值,我们需要找出2个点,使得2个点之间各边权值的异或合最大

题解:
在这里插入图片描述

假设存在如上的一棵树,我们需要计算1号点和2号点之间的异或值也就是 v 1 v_1 v1^ v 2 v_2 v2,我们可以转化为 v 1 ∧ v 3 ∧ v 3 ∧ v 2 v_1\wedge v_3\wedge v_3\wedge v_2 v1v3v3v2,也就是 v 1 v_1 v1到根节点的异或值 异或上 v 2 v_2 v2到根节点的异或值。我们只需要预处理好每个点到根节点的异或值,这一题也就转换成了第二题

代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = 200010;

int n;
int h[N], e[M], c[M], ne[M], cnt;
int a[N], son[3000000][2], idx;

void add(int u, int v, int w)
{
    
    
    e[cnt] = v, c[cnt] = w, ne[cnt] = h[u], h[u] = cnt ++ ;
}

void dfs(int u, int father, int sum)
{
    
    
    a[u] = sum;
    for (int i = h[u]; ~i; i = ne[i])
    {
    
    
        int j = e[i];
        if (j != father) dfs(j, u, sum ^ c[i]);
    }
}

void insert(int x)
{
    
    
    int p = 0;
    for (int i = 30; i >= 0; i -- )
    {
    
    
        int &s = son[p][x >> i & 1];
        if (!s) s = ++ idx;
        p = s;
    }
}

int search(int x)
{
    
    
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i -- )
    {
    
    
        int s = x >> i & 1;
        if (son[p][!s])
        {
    
    
            res += 1 << i;
            p = son[p][!s];
        }
        else p = son[p][s];
    }
    return res;
}

int main()
{
    
    
    memset(h, -1, sizeof h);

    cin >> n;
    for (int i = 0; i < n - 1; i ++ )
    {
    
    
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
        add(v, u, w);
    }

    dfs(0, -1, 0);

    for (int i = 0; i < n; i ++ ) insert(a[i]);

    int res = 0;
    for (int i = 0; i < n; i ++ ) res = max(res, search(a[i]));

    cout << res << endl;

    return 0;
}


猜你喜欢

转载自blog.csdn.net/jahup/article/details/114224061
今日推荐