ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

踹树(Tire 字典树)

2021-01-09 21:33:53  阅读:272  来源: 互联网

标签:ch Tire tire int include now 字典


Tire 字典树

~~ 比 KMP 简单多了,无脑子选手学不会KMP,不会结论题~~
自己懒得造图了OI WIKI 真棒
字典树大概长这么个亚子

呕吼真棒

  1. 就是将读进去的字符串根据当前的字符是什么和所处的位置构成一棵树
  2. 例如图中\(1-->2-->5\)这一条路就是字符串\(aa\)那\(1-->4-->8-->13\)就是字符串\(cab\)
    貌似也没有什么东西的,题目的话基本就是套板子,唯一奇怪的就是把一个数二级化建树跑一些奇奇怪怪的东西

字符串:

struct Tire{
    int tire[][] ,Tire_num;
    void add(char *s){
        int now = 0 , 
        for(int i = 1 ; i <= len ;i++) {
            if(!tire[now][s[i]]) tire[now][s[i]] = +++Tire
            now = tire[now][s[i]];
        }
    }
}

二进制:

struct Tire{
    int tire[][] ,Tire_num;
    void add(int x){
        int now = 0 , 
        for(int i = 31 ; i >= 0 ;i--) {
            int ch = (x>>(i)&1);
            if(!tire[now][ch]) tire[now][ch] = +++Tire
            now = tire[now][ch];
        }
    }
}

踹树的时间复杂度其实不低普遍为\(\sum\limits_{i = 1}^{n}~|s_i|\)

例题
题目洛谷也有
这个题就是很显然的板子

  • 询问输入字符串是否为已经输入串的子串
  • 直接边建树边查询就OK

建树并查询的时候会有2种情况

  1. 一直没有添加新的字母一直到该字符的最后一个,说明该字符串为已加入串的子串
  2. 遍历到了某个字符串的最后一个字符,说明已经添加子串为该字符串的子串

然后就没有然后了,你就把它切了(多测不清我是sb)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#define ll long long
using namespace std;
const int N = 1e6+100;
int read() {
    int s = 0 , f = 0 ; char ch = getchar() ;
    while(!isdigit(ch)) f |= (ch == '-') , ch = getchar();
    while(isdigit(ch)) s = s * 10 + (ch ^ 48) , ch = getchar();
    return f ? -s : s;
}
char s[20];
struct Tire{
    int Tir_num ,tir[N][11],vis[N];
    int add(char *s) {
        int len = strlen(s+1), now = 0;
        bool flag = 0;
        for(int i = 1 ; i <= len ;i++) {
            int ch = s[i]-'0';
            if(!tir[now][ch]) tir[now][ch] = ++Tir_num;
            else if(i == len) flag = 1;
            // cout << Tir_num<<" ";
            now = tir[now][ch];
            if(vis[now]) flag = 1;
            // cout <<now<<" "<< flag <<" ";
        }
        vis[now] = 1;
        // puts("");
        return flag;
    }
    void clear(){
        memset(tir,0,sizeof(tir));
        memset(vis,0,sizeof(vis));
        Tir_num = 0;
        // puts("LKP AK IOI");
    }
}tire;
int main() {
    int T = read() ;
    while(T--) {
        tire.clear();
        int n = read();
        int cnt = 0;
        for(int i = 1 ; i <= n;i++){
            scanf("%s", s+1);
            cnt += tire.add(s);
        }
       if(cnt) puts("NO");
       else puts("YES");
    }
    system("pause");
    return 0;
}

二进制的例题

  • 根据\(xor\)的性质考虑贪心
  • \(1\)^\(1\) \(=0~~\) \(0\) ^ \(1 = 1\) \(~~~~0\) ^ \(0 = 1\)
  • 尽可能的让二级制下的高位存在1
    那么按照这个贪心思路
void query(int x) {
    int now = 0 , ans = 0;
    for(int i = 31 ; i >= 0 ;i-- ) {
        int ch = ((x >> i) & 1) , temp = ch ^ 1;
        if(tir[now][temp]) 
            now = tir[now][temp] ,
            ans = ((ans << 1) | 1);
        else {
            now = tir[now][ch];
            ans <<= 1;
        }
    }
    return ans;
}

还是贴一下完整代码吧

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#define ll long long
using namespace std;
const int N = 4000010;
int read() {
    int s = 0 , f = 0 ; char ch = getchar() ;
    while(!isdigit(ch)) f |= (ch == '-') , ch = getchar();
    while(isdigit(ch)) s = s * 10 + (ch ^ 48) , ch = getchar();
    return f ? -s : s;
}
struct Tire{
    int  tire[N][2], Tir_num;
    void add(int x) {
        int now = 0 ;
        for(int i = 31 ; i >= 0 ;i--) {
            int ch = ((x>>i) & 1);
            if(!tire[now][ch]) tire[now][ch] = ++Tir_num;
            now = tire[now][ch];
        }
    }
    int query(int x){
        int now = 0 , ans = 0;
        for(int i = 31 ; i >= 0 ;i--) {
            int ch = ( (x >> i) & 1) , temp = ch ^ 1;
            if(tire[now][temp]) now = tire[now][temp],ans = (ans << 1) | 1;
            else now = tire[now][ch], ans <<= 1;
        }
        return ans;
    }
}tir;

int a[N];
int main() {
    int n = read();
    int ans = -1;
    for(int i = 1 ; i <= n ;i++) {
        a[i] = read(); 
        tir.add(a[i]);
        ans = max(ans,tir.query(a[i]));
    }
    printf("%d",ans);
    system("pause");
    return 0;
}

踹树能做的AC自动机也能干,好吧Tire树AC自动机的一部分
自己说的仅仅是一部分,OI wiki讲的很详细,对题目分类讲的也很详细,觉得我写的不好可以去OI wiki

标签:ch,Tire,tire,int,include,now,字典
来源: https://www.cnblogs.com/-wzd233/p/14256520.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有