-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathSAM.cpp
68 lines (68 loc) · 1.92 KB
/
SAM.cpp
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
// any path start from root forms a substring of S
// occurrence of P : iff SAM can run on input word P
// number of different substring : ds[1]-1
// total length of all different substring : dsl[1]
// max/min length of state i : mx[i]/mx[mom[i]]+1
// assume a run on input word P end at state i:
// number of occurrences of P : cnt[i]
// first occurrence position of P : fp[i]-|P|+1
// all position of P : fp of "dfs from i through rmom"
const int MXM = 1000010;
struct SAM{
int tot, root, lst, mom[MXM], mx[MXM]; //ind[MXM]
int nxt[MXM][33]; //cnt[MXM],ds[MXM],dsl[MXM],fp[MXM]
// bool v[MXM]
int newNode(){
int res = ++tot;
fill(nxt[res], nxt[res]+33, 0);
mom[res] = mx[res] = 0; //cnt=ds=dsl=fp=v=0
return res;
}
void init(){
tot = 0;
root = newNode();
lst = root;
}
void push(int c){
int p = lst;
int np = newNode(); //cnt[np]=1
mx[np] = mx[p]+1; //fp[np]=mx[np]-1
for(; p && nxt[p][c] == 0; p = mom[p])
nxt[p][c] = np;
if(p == 0) mom[np] = root;
else{
int q = nxt[p][c];
if(mx[p]+1 == mx[q]) mom[np] = q;
else{
int nq = newNode(); //fp[nq]=fp[q]
mx[nq] = mx[p]+1;
for(int i = 0; i < 33; i++)
nxt[nq][i] = nxt[q][i];
mom[nq] = mom[q];
mom[q] = nq;
mom[np] = nq;
for(; p && nxt[p][c] == q; p = mom[p])
nxt[p][c] = nq;
} }
lst = np;
}
void calc(){
calc(root);
iota(ind,ind+tot,1);
sort(ind,ind+tot,[&](int i,int j){return mx[i]<mx[j];});
for(int i=tot-1;i>=0;i--)
cnt[mom[ind[i]]]+=cnt[ind[i]];
}
void calc(int x){
v[x]=ds[x]=1;dsl[x]=0; //rmom[mom[x]].push_back(x);
for(int i=1;i<=26;i++){
if(nxt[x][i]){
if(!v[nxt[x][i]]) calc(nxt[x][i]);
ds[x]+=ds[nxt[x][i]];
dsl[x]+=ds[nxt[x][i]]+dsl[nxt[x][i]];
} } }
void push(const string& str){
for(int i = 0; i < str.size() ; i++)
push(str[i]-'a'+1);
}
} sam;