其他分享
首页 > 其他分享> > 字典树

字典树

作者:互联网

概念:

字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入和查找。
image

模板:

字符串trie模板

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx;
char str[N];
//插入字符串
void insert(char str[]) {
    int p = 0;  // p从0开始,
    for (int i = 0; str[i]; i++) {
        int u = str[i] - 'a';  //转换成数字0-25
        if (son[p][u] == 0)
            son[p][u] = ++idx;  //如果之前没出现过,就记录他的编号,从开头开始,如果之前在一样的位置,出翔了一样的字母
        //就不用新的编号,沿用之前的编号。如果之前,在对应的位置,就记录新的编号。一样的位置一样的字母就是一样的编号,每一种编号仅代表对应位置的对应字母,其中一个不一样,编号一定是不一样的
        p = son[p][u];  // p在这里还担任指针的作用
    }
    cnt[p]++;  //对应的编号(最后一个单字符)+1
}
//查询字符串
int ask(char str[]) {
    int p = 0;
    for (int i = 0; str[i]; i++) {
        int u = str[i] - 'a';
        if (son[p][u] == 0)
            return 0;  //当对应位置对应的字母编号是0的话,就说明没找到
        p = son[p][u];  //指针往下找
    }
    return cnt[p];  //返回对应编号出现的次数
}
int main() {
    int n;
    scanf("%d", &n);
    while (n--) {
        char op[2];
        scanf("%s%s", op, str);
        if (op[0] == 'I') {
            insert(str);
        } else {
            printf("%d\n", ask(str));
        }
    }
    return 0;
}

01字典树模板

#include <algorithm>
#include <iostream>
using namespace std;
const int N = 100010;
int a[N], son[N * 31][2], idx;
void build(int x) {  //建树
    int p = 0;
    for (int i = 30; i >= 0; i--) {
        int u = x >> i & 1;  //取二进制的首位,
        if (!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
}
int ask(int x) {
    int p = 0, ans = 0;
    for (int i = 30; i >= 0; i--) {
        int u = x >> i & 1;
        if (son[p][!u]) {
            p = son[p][!u];
            ans =ans * 2 + !u;  //这里类似于二进制转化成十进制,就是左移后奖赏你想要的末尾二进制数
        } else {
            p = son[p][u];
            ans = ans * 2 + u;
        }
    }
    return ans;
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    int ans = 0;
    for (int i = 0; i < n; i++) {
        build(a[i]);
        int t = ask(a[i]);
        ans = max(ans, t ^ a[i]);
    }

    printf("%d\n", ans);
    return 0;
}

例题:

于是他错误的点名开始了

wudima的XOR小游戏

View Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
int a[N], son[N * 31][2], idx;
void build(int x) {
    int p = 0;
    for (int i = 30; i >= 0; i--) {
        int u = x >> i & 1;
        if (!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
}
int ask(int x) {
    int p = 0, ans = 0;
    for (int i = 30; i >= 0; i--) {
        int u = (x >> i) & 1;
        if (son[p][u]) {
            p = son[p][u];
        } else {
            p = son[p][!u];
            ans |= (1 << i);
        }
    }
    return ans;
}

int dfs(int l, int r, int now) {
    if (l > r || now < 0) return 0;
    int zero = 0;
    int mid = l - 1;
    for (int i = l; i <= r; i++) {
        if ((a[i] >> now) & 1) {
            mid = i - 1;
            break;
        } else {
            zero++;
        }
    }
    if (zero % 2 == 0) {
        return max(dfs(l, mid, now - 1), dfs(mid + 1, r, now - 1));
    } else {
        int ans = 2e9;
        for (int i = l; i <= mid; i++) {
            build(a[i]);
        }
        for (int i = mid + 1; i <= r; i++) {
            int t = ask(a[i]);
            ans = min(ans, t);
        }
        return ans;
    }
}
signed main() {
    int n;
    cin >> n;
    for (int i = 1; i <= 2 * n; i++) {
        cin >> a[i];
    }
    sort(a + 1, a + n * 2 + 1);
    int res = dfs(1, 2 * n, 30);
    cout << res;
    return 0;
}

Trie字符串统计

最大异或对

最长异或值路径

牛异或

D. Binary Spiders

View Code
#include <bits/stdc++.h>
#include<iostream>
using namespace std;
const int N = 3e5 + 10;
int a[N];
map<int, int> id;
map<int, vector<int> > mp;
vector<int> res;
int son[N * 31][2], idx;
int n, k;
int get(int x) {
    int cnt = 0;
    while (x) {
        x >>= 1;
        cnt++;
    }
    return cnt;
}

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

int query(int x) {
    int p = 0, ans = 0;
    for (int i = 30; i >= 0; i--) {
        int u = x >> i & 1;
        if (son[p][!u]) {
            p = son[p][!u];
            ans = ans * 2 + !u;
        } else {
            p = son[p][u];
            ans = ans * 2 + u;
        }
    }
    return ans;
}

int main() {
    cin >> n >> k;
    int m = get(k);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        int x = a[i] >> m;
        mp[x].push_back(a[i]);
        id[a[i]] = i;
    }

    if (k == 0) {
        cout << n << endl;
        for (int i = 1; i <= n; i++) {
            cout << i << " ";
        }
        return 0;
    } else {
        for (auto it : mp) {
            memset(son, 0, 4 * 2 * (idx + 4));
            idx = 0;
            vector<int> p = it.second;
            int l = -1, r = -1;
            int dex = -1;
            for (int i = 0; i < p.size(); i++) {
                int now = p[i];
                dex = id[now];
                insert(now);
                int t = query(now);
                if ((t ^ now) >= k) {
                    l = id[now];
                    r = id[t];
                    break;
                }
            }

            if (l!=-1 && r!=-1) {
                res.push_back(l);
                res.push_back(r);
            } else if (dex > 0) {
                res.push_back(dex);
            }
        }

        if (res.size() <= 1) {
            puts("-1");
        } else {
            printf("%d\n", res.size());
            for (int i = 0; i < res.size(); i++) {
                printf("%d ", res[i]);
            }
        }
    }
}

Ex - Multiply or Divide by 2

View Code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int tr[N * 31][2];
int cnta[N * 31], cntb[N * 31];
bool flag = 1;
int n;
int idx;
int ans;
int count(int x) {
    int res = 0;
    while (x) x /= 2, res++;
    return res;
}
void dfs(int u) {
    if (tr[u][0]) {
        ans += abs(cnta[tr[u][0]] - cntb[tr[u][0]]);
        dfs(tr[u][0]);
    }
    if (tr[u][1]) {
        if (cntb[tr[u][1]] > cnta[tr[u][1]]) {
            flag = 0;
            return;
        }
        ans += abs(cnta[tr[u][1]] - cntb[tr[u][1]]);
        dfs(tr[u][1]);
    }
}
signed main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        int p = 0;
        for (int j = count(x); j >= 0; j--) {
            int u = (x >> j) & 1;
            if (!tr[p][u]) tr[p][u] = ++idx;
            p = tr[p][u];
            cnta[p]++;
        }
    }
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        int p = 0;
        for (int j = count(x); j >= 0; j--) {
            int u = (x >> j) & 1;
            if (!tr[p][u]) tr[p][u] = ++idx;
            p = tr[p][u];
            cntb[p]++;
        }
    }
    dfs(0);
    if (flag)
        cout << ans << endl;
    else
        cout << "-1" << endl;
}

D2. 388535 (Hard Version)

标签:int,tr,son,++,ans,include,字典
来源: https://www.cnblogs.com/OverThink/p/16545617.html