--- id: string-suffix title: "String Suffix Structures" author: Benjamin Qi, Siyong Huang description: "Suffix Automata, Suffix Trees, and (TBD) Palindromic Trees" prerequisites: - Platinum - String Searching frequency: 0 --- export const metadata = { problems: { auto: [ new Problem("Plat", "Standing Out from the Herd", "768", "Hard", false, [], ""), ], tree: [ new Problem("CF", "Security", "contest/1037/problem/H", "Hard", false, ["Suffix Tree"], ""), ] } }; ## Suffix Automaton The **Suffix Automaton** is a directed acyclic word graph (DAWG), such that each path in the graph traces out a distinct substring of the original string. ### Resources Explanation of Suffix Automata Excellent Suffix Automaton tutorial Most problems can be solved with Suffix Arrays, Suffix Automata, or Suffix Trees. The solution may just be slightly easier/harder with the various data structures. ### Problems ```cpp #include #include #include FILE * IN, * OUT; typedef long long ll; const int MN = 1e5+10, MM = MN*2; char s[MN]; std::vector down[MM]; int N, v[MM], c[MM][26], l[MM], d[MM], topo[MM], T, X; ll f[MN], cnt[MM]; bool u[MM]; /* Key Variables: s: input strings down: link tree of automaton v: information regarding which cow each node belongs to c: child array of automaton l: link (of automaton) d: depth (of automaton) topo: toposort (of automaton) T, X: counters for toposort and automaton f: answer cnt: number of ways to reach a node from the root u: visited array for toposort */ //add cow b to value a //value = -1: no cow assigned //value = -2: multiple cows assigned //value = 0..N: cow id void merge(int& a, int b) { if(!~a) a=b; else if(~b&&a!=b) a=-2; } //template automaton code int append(int p, char x) { if(~c[p][x]) { int q=c[p][x]; if(d[q]==d[p]+1) return q; else { ++X; for(int i=0;i<26;++i) c[X][i]=c[q][i]; l[X]=l[q], d[X]=d[p]+1; l[q]=X; for(;~p&&c[p][x]==q;p=l[p]) c[p][x]=l[q]; return l[q]; } } int n = ++X; d[n]=d[p]+1; for(;~p&&!~c[p][x];p=l[p]) c[p][x]=n; if(!~p) l[n]=0; else { int q=c[p][x]; if(d[q]==d[p]+1) l[n]=q; else { ++X; for(int i=0;i<26;++i) c[X][i]=c[q][i]; l[X]=l[q], d[X]=d[p]+1; l[n]=l[q]=X; for(;~p&&c[p][x]==q;p=l[p]) c[p][x]=l[q]; } } return n; } //DFS along links void dfs2(int n=0) { for(int x:down[n]) { dfs2(x); merge(v[n], v[x]); } } //DFS along suffix automaton. This builds the toposort void dfs(int n=0) { u[n]=1; for(int i=0;i<26;++i) { int y=c[n][i]; if(~y && !u[y]) dfs(y); } topo[T++] = n; } int main(void) { IN = fopen("standingout.in", "r"), OUT = fopen("standingout.out", "w"); memset(v, -1, sizeof v); memset(c, -1, sizeof c); fscanf(IN, "%d", &N); d[0]=0, l[0]=-1; for(int i=0;i=0;--i) { x=topo[i]; for(int j=0;j<26;++j) if(~c[x][j]) cnt[c[x][j]]+=cnt[x];//count number of paths from root to a node if(v[x]>=0) f[v[x]]+=cnt[x];//if this node is associated with a unique cow, add to answer } for(int i=0;i ## Suffix Tree The **Suffix Tree** is a trie that contains all suffixes of a string. Naively, this would take up $O(N^2)$ memory, but *path compression* enables it to be represented and computed in linear memory. ### Resources Explanation of Ukkonen's Suffix Tree Algorithm Implementation of Ukkonen's Algorithm ### Problems ### Generate Suffix Array A suffix array can be generated by the suffix tree by taking the dfs traversal of the suffix tree. ```cpp int N, sa[MN];//length of string, suffix array struct edge { public: int n, l, r;//node, edge covers s[l..r] explicit operator bool() const {return n!=-1;} } c[MN*2][26]; void dfs(int n=0, int d=0) { bool c=0;// Has child. If false, then this node is a leaf for(int i=0;i<26;++i) if(c[n][i]) { c=1; dfs(c[n][i].n, d+c[n][i].r-c[n][i].l); } if(!c) sa[ctr++]=N-d; } ``` ## Palindromic Tree (Still don't know what these are!! Benq help!) * String Suffix Structures * Suffix Tree * [CF](https://codeforces.com/blog/entry/16780) * [CP-Algo](https://cp-algorithms.com/string/suffix-tree-ukkonen.html) * O(nlogn) suffix array usually suffices * More on Palindromic Tree * [Palindrome Partition](https://codeforces.com/contest/932/problem/G) * [Partial Solution](https://codeforces.com/blog/entry/19193) * [Palindromic Magic (HARD)](https://codeforces.com/contest/1081/problem/H)