字典树

trie树(字典树)学习笔记

匿名 (未验证) 提交于 2019-12-02 23:53:01
例题 于是他错误的点名开始了 #include <cstdio> #include <algorithm> #include <cstring> using namespace std; struct node { bool wrd, vis; int ch[26]; }trie[500009]; int siz = 1; inline void insert(char* str) { int t = 1, len = strlen(str); for(int i = 0; i < len; i++) { if(!trie[t].ch[str[i] - 'a']) t = trie[t].ch[str[i] - 'a'] = ++siz; else t = trie[t].ch[str[i] - 'a']; } trie[t].wrd = true; } inline int search(char* str) { int t = 1, len = strlen(str); for(int i = 0; i < len; i++) { if(!trie[t].ch[str[i] - 'a']) return 0; else t = trie[t].ch[str[i] - 'a']; } if(trie[t].wrd) { if(trie[t].vis) return -1;

trie字典树

匿名 (未验证) 提交于 2019-12-02 23:49:02
cat,cash,app,apple,aply,ok。 也许你的第一个想法是暴力搜索每一个单词,但是复杂度很很很很高啊 有一种东西叫做字典树,字典树的根节点连出来的每一条边存的就是出现的首字母, 然后但此后边的字母我们可以在后边存上, 这样每一个单词的最后一个单词就是最后存的 那条边,这样我们可以在那条代表着最后单词的边的下一个节点处打一个标记,然后表示一个单词就结束了; like this 把每一个单词放到字典树中... void add ( string ch ) { int len = ch . size (), root = 0 , x ; for ( int i = 0 ; i < len ; i ++) { x = ch [ i ] - 'a' ; if (! trie [ root ][ x ]) trie [ root ][ x ] = ++ tot ; tr [ trie [ root ][ x ]] = 1 ; root = trie [ root ][ x ]; } tr [ trie [ root ][ x ]] = 1 ; } int query ( string ch ) { int len = ch . size (), root = 0 , ans = 0 ; int x ; for ( int i = 0 ; i < len ; i ++) { x

字典树(Trie树)

匿名 (未验证) 提交于 2019-12-02 23:47:01
字典树在多个单词匹配长句或者求单词的相似前缀时非常好用。 下面是他的结构: 字典树的每一条边就是一个字母,按照单词字母顺序给节点排序号。 这里用二维数组代表线段树的结构: \(tree[i][j]=k\) \(i\) 代表节点序号, \(j\) 代表是上一个节点下面的哪个字母节点( \(a-z\) 分为 \(0-25\) ), \(k\) 代表下一个节点的序号。 如果要查找单词还需要一个is_end数组来记录保存哪些节点是末节点。 下面是字典树的插入节点函数: void insert(string s,int node)//node从0开始 { for (int i = 0; s[i]; i++) { int num = s[i] - 'a'; if (trie[node][num] == 0) trie[node][num] = ++tot;//全部变量,让序号一直增长 node = trie[node][num];//获取下一个点的序号 } //is_end[node] = 1;//如果到了终点给下一个节点赋结束符 } 查找函数: bool find(string s,int node)//找前缀或者找单词 { for (int i = 0; s[i] ; i++) { int num = s[i] - 'a'; if (trie[node][num] == 0) return

Trie树【字典树】浅谈

匿名 (未验证) 提交于 2019-12-02 23:43:01
最近随洛谷日报看了一下Trie树,来写一篇学习笔记。 Trie树:支持字符串前缀查询等(目前我就学了这些qwq) 一般题型就是给定一个模式串,几个文本串,询问能够匹配前缀的文本串数量。 首先,来定义下Trie树:其根节点为空,定义如下数组: #include<cstdio> #include<iostream> #include<cstring> #include<string> using namespace std; int trie[500000][30],p[500000];//trie[u][x]用来表示u串中x字符所指的节点编号 char ch[500000];//ch数组是字符串,每次插入,p数组是标记数组,插入完后打标记 int main(){ return 0; } 下面给出插入代码: #include<cstdio> #include<iostream> #include<cstring> #include<string> using namespace std; int trie[500000][30],p[500000]tot; char ch[500000]; inline void Insert(char *ch){ int u=0,len=strlen(ch+1); for(int i=1;i<=len;++i){ int x=ch[i]-'a';/

字典树板子

对着背影说爱祢 提交于 2019-12-02 13:03:08
基本的操作 1.定义(即定义结点) next是表示每层有多少种类的数,如果只是小写字母,则26即可,若改为大小写字母,则是52,若再加上数字,则是62了,这里根 据题意来确定。 cnt可以表示一个字典树到此有多少相同前缀的数目,这里根据需要应当学会自由变化。 1 struct node{ 2 int cnt; 3 struct node *next[26]; 4 node(){ 5 cnt=0; 6 memset(next,0,sizeof(next)); 7 } 8 }; View Code 2.插入(即建树过程) 构建Trie树的基本算法也很简单,无非是逐一把每则单词的每个字母插入Trie。插入前先看前缀是否存在。如果存在,就共享,否则 创建对应的节点和边。比如要插入单词add(已经插入了单词“ad”),就有下面几步: 考察前缀"a",发现边a已经存在。于是顺着边a走到节点a。 考察剩下的字符串"dd"的前缀"d",发现从节点a出发,已经有边d存在。于是顺着边d走到节点ad 考察最后一个字符"d",这下从节点ad出发没有边d了,于是创建节点ad的子节点add,并把边ad->add标记为d。 1 <pre name="code" class="cpp">void buildtrie(char *s){ 2 node *p = root; 3 node *tmp = NULL; 4

HDU 2846 Repository(字典树)

自闭症网瘾萝莉.ら 提交于 2019-12-02 03:44:25
嗯... 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846 这与裸的字典树略有差别: 因为题目要求有n个字符串,m个询问 问字符串在n个字符串中出现过多少次, 即为一个字串的问题,所以我们把一个字符串拆开分别建树。 eg: abcd 中有a,b,c,d,abcd,bcd,cd,bc,abc... 我们可以将abcd拆成abcd bcd cd d 分别建树 注意: abab会导致重复,所以用flag标记:若此编号不同于所给编号(此后缀在本要查的字符串中没有)才加1,这样就避免了重复。 AC代码: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 5 using namespace std; 6 7 int ch[500005][30]; 8 int flag[500005]; 9 int val[500005]; 10 int cnt = 1; 11 12 inline int ids(char c){ 13 return c - 'a'; 14 } 15 16 inline void build(char *s, int k){ 17 int u = 0; 18 int len = strlen(s); 19 for(int i = 0; i < len;

UVA1401 (字典树加简单dp)

爷,独闯天下 提交于 2019-12-01 12:08:56
#pragma GCC optimize(2) #include <bits/stdc++.h> #define ll long long using namespace std; const int N = 5e5+10; const int mod=20071027; const int sigma_size=26; int dp[N]; char str[N]; char s[105]; struct Trie{ int ch[N][sigma_size]; int val[N]; int sz; Trie(){sz=1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c-'a';} void reset(){memset(ch,0,sizeof(ch));memset(val,0,sizeof(val));sz=1;} void insert(char *s,int v) { int u=0,n=strlen(s); for(int i=0;i<n;i++) { int c=idx(s[i]); if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } val[u]=v; } int

洛谷-P2292-L语言(字典树)

a 夏天 提交于 2019-11-30 17:02:08
链接: https://www.luogu.org/problem/P2292 题意: 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。 一段文章T是由若干小写字母构成。一个单词W也是由若干小写字母构成。一个字典D是若干个单词的集合。我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词。 例如字典D中包括单词{‘is’, ‘name’, ‘what’, ‘your’},则文章‘whatisyourname’是在字典D下可以被理解的,因为它可以分成4个单词:‘what’, ‘is’, ‘your’, ‘name’,且每个单词都属于字典D,而文章‘whatisyouname’在字典D下不能被理解,但可以在字典D’=D+{‘you’}下被理解。这段文章的一个前缀‘whatis’,也可以在字典D下被理解,而且是在字典D下能够被理解的最长的前缀。 给定一个字典D,你的程序需要判断若干段文章在字典D下是否能够被理解。并给出其在字典D下能够被理解的最长前缀的位置。 思路: 建字典树, 对每个单词在句子上的结束做标记, 说明可以另开一次. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector

HDU-1251-统计难题(字典树)

痞子三分冷 提交于 2019-11-30 10:12:26
链接: https://vjudge.net/problem/HDU-1251 题意: Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). 思路: 直接考虑字典数, 每个节点记录经过的次数,次数就是前缀数目. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector> //#include <memory.h> #include <queue> #include <set> #include <map> #include <algorithm> #include <math.h> #include <stack> #include <string> #include <assert.h> #include <iomanip> #define MINF 0x3f3f3f3f using namespace std; typedef long long LL; const int INF = 1e9; const int MAXN = 1e6+10; int cnt, n; char word[100]; struct Node { int Ends; int Pass;

HDU 6625 (01字典树)

谁都会走 提交于 2019-11-30 07:15:30
题意: 给定两个长为n的数组a和b; 重新排列a和b,生成数组c,c[i]=a[i] xor b[i]; 输出字典序最小的c数组。 分析: 将a中的数插入一颗01字典树a中; 将b中的数插入一颗01字典树b中; 在trie树上查找n次,每次同时在a和b中下移一层; if 能同时走0,则同时走0; else if 能同时走1,则同时走1; else if 树a能走0&&树b能走1,则a走0、b走1; else if 树a能走1&&树b能走0,则a走1、b走0; else 向c中插入一个新数为这两个节点的异或值; 最后对c排序。 复杂度O(T*n*30) #include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; typedef long long LL; struct Trie01{ int ch[35 * maxn][2]; int cnt[35*maxn]; int node_cnt; inline void init(){ node_cnt = 1; memset(ch[0],0,sizeof(ch[0])); } inline void Insert(LL x){ int cur = 0; for(int i = 30;i >= 0;--i){ int idx = (x >> i) & 1; if(