标准版
含义详解
a[p][ch]的值为下一个节点的层数,即idx(第几个节点),ch为字符指针配合p
即可确定节点所在的具体层数与位置(N为所有字符串总长度,每层26个节点)
a[p][ch]第一维共N 26个节点, idx最大为N 26 - 1
通过 p = a[p][ch]来实现更新指向下一个节点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
28const int N = ;
int a[N][26], idx; //根节点在第0层
char str[N];
bool end[N]; //结束数组(在最后一个元素下一层)
void insert()
{
int p = 0; //根节点为 0, p为在树中的层数
for(int i = 0; str[i]; i ++ )
{
char ch = str[i] - 'a'; //ch为字符指针
if(!a[p][ch]) a[p][ch] = ++ idx;
//字符指针指向空,创建节点(a[p][ch]的值为下一层,即字符指针指向的地方),新节点
p = a[p][ch]; //变换到下一个节点(下一层)
}
end[p] = true; //结束标记,下一层的位置标记true
}
bool search()
{
int p = 0; //根节点,p为层数
for(int i = 0; str[i]; i ++ )
{
char ch = str[i] - 'a'; //字符指针
if(!a[p][ch]) return false; //指向空,返回false
p = a[p][ch]; //节点变换到下一个(下一层)
}
return end[p]; //整个字符串成功便利,判断是否有结束标记
}
例题一: 前缀统计
给定N个字符串S1,S2…SN,接下来进行M次询问,每次询问给定一个字符串T,求S1~SN中有多少个字符串是T的前缀。
输入字符串的总长度不超过106,仅包含小写字母。
输入格式
第一行输入两个整数N,M。
接下来N行每行输入一个字符串Si。
接下来M行每行一个字符串T用以询问。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
输入样例:
1 | 3 2 |
输出样例:
1 | 2 |
题意分析
对前n个字符串进行建树,即插入树的insert()操作,对于后m个字符进行search()操作, 判断每个给出的字符串str在n中有多少个为
str的前缀。
细节处理
end[p] -> 变为cnt[p],从0 1变为统计次数,查询时sum += cnt[p], 遇到a[p][ch]指向空则break
退出for循环后 return sum
代码
1 |
|
例题二: 最大异或对
在给定的N个整数A1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数N。
第二行输入N个整数A1~AN。
输出格式
输出一个整数表示答案。
数据范围
1≤N≤105,
0≤Ai<231
输入样例:
1 | 3 |
输出样例:
3
题意分析
将每个A_i视为一个31位的01串,对这n个数进行建树依次insert($A_i$),共有N * 32个节点,每个节点为0 1其中之一
之后对每个串进行查询操作,由于是异或,则应每次判断是否存在num相异的节点,存在则 p = a[p][!num]更新,
res对应位变为1(xor相异结果为true)不存在则按原来更新p = a[p][num], 但res此时对应位不做改变
代码
1 |
|