【字典树】洛谷 P2922 Secret Message G
2021-05-14 20:20:00 # ACM

题链

维护两个数组$v1[]$,$v2[]$,$v1[]$用于标记,$v2[]$用于记录$v1$的后缀和;
对于一个询问,如果在字典树上向下查找直到查找不到时,此时答案就是访问到的$v1[]$的和,如果查找完了,也就是说字典树上还有比询问更长的串,则答案也是访问到的$v1[]$的和,但是得加上此时的后缀和$v2[]$,因为当前$v2[]$包含$v1[]$,所以还得减去$v1[]$;

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ll long long
#define ULL unsigned long long
#define Pair pair<LL,LL>
#define ls rt<<1
#define rs rt<<1|1
#define Pi acos(-1.0)
#define eps 1e-6
#define DBINF 1e100
#define mod 998244353
#define MAXN 1e18
#define MS 150000

int n,m;
int p[500009][3];
int v1[500009];
int v2[500009];
int step;

void insert(int len){
int cc = 0;
for(int i=1;i<=len;i++){
int x;
cin >> x;
if(!p[cc][x]) p[cc][x] = ++step;
cc = p[cc][x];
v2[cc]++;
}
v1[cc]++;
}

int find(int len){
int cc = 0;
int ans = 0;
int flag = 0;
for(int i=1;i<=len;i++){
int x;
cin >> x;
if(!p[cc][x]){
flag = 1;
}
if(flag) continue;
cc = p[cc][x];
ans += v1[cc];
}
if(flag){
return ans;
}
ans += v2[cc];
ans -= v1[cc];
return ans;
}

int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i=1;i<=n;i++){
int len;
cin >> len;
insert(len);
}
while(m--){
int len;
cin >> len;
cout << find(len) << "\n";
}

return 0;
}
Prev
2021-05-14 20:20:00 # ACM
Next