Tainel

Suffix Automaton

Feb 13th, 2023 (edited)
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.81 KB | Source Code | 0 0
  1. #pragma once
  2.  
  3. #include"template.hpp"
  4.  
  5. template<typename Char=char>
  6. class suffix_automaton{
  7.     using str=std::basic_string<Char>;
  8.     using view=std::basic_string_view<Char>;
  9.     std::vector<bool>terminal;
  10.     std::vector<std::vector<i32>>inv_link;
  11.     std::vector<std::map<Char,i32>>next{{}};
  12.     std::vector<i32>link{-1},len{0},firstpos{-1},terminal_paths_from;
  13.     std::vector<i64>substrings_from,paths_from;
  14.     str text;
  15.     i32 size=1;
  16.     bool extra=false;
  17.     suffix_automaton(){}
  18.     void reserve_memory(const i32 n){
  19.         ASSERT(n>=0);
  20.         text.reserve(n);
  21.         const i32 max_size=std::max(n+1,2*n-1);
  22.         next.reserve(max_size);
  23.         link.reserve(max_size);
  24.         len.reserve(max_size);
  25.         firstpos.reserve(max_size);
  26.     }
  27.     void extend(const Char c,i32&last){
  28.         ASSERT(0<=last&&last<size);
  29.         text.push_back(c);
  30.         i32 p=last;
  31.         last=push_new_state();
  32.         len[last]=len[p]+1;
  33.         firstpos[last]=len[p];
  34.         do{next[p][c]=last,p=link[p];}UNTIL(p==-1||next[p].count(c));
  35.         if(p==-1){link[last]=0;}
  36.         else{
  37.             const i32 q=next[p][c];
  38.             if(len[q]==len[p]+1){link[last]=q;}
  39.             else{
  40.                 const i32 cl=push_copy_state(q);
  41.                 len[cl]=len[p]+1;
  42.                 link[last]=link[q]=cl;
  43.                 do{next[p][c]=cl,p=link[p];}UNTIL(p==-1||next[p].at(c)!=q);
  44.             }
  45.         }
  46.     }
  47.     i32 push_new_state(){
  48.         next.emplace_back();
  49.         link.push_back(-1);
  50.         len.push_back(0);
  51.         firstpos.push_back(-1);
  52.         return size++;
  53.     }
  54.     i32 push_copy_state(const i32 state){
  55.         ASSERT(0<=state&&state<size);
  56.         next.push_back(next[state]),
  57.         link.push_back(link[state]);
  58.         len.push_back(len[state]);
  59.         firstpos.push_back(firstpos[state]);
  60.         return size++;
  61.     }
  62.     void count_paths(){
  63.         ASSERT(extra);
  64.         terminal_paths_from.resize(size);
  65.         substrings_from.resize(size);
  66.         paths_from.resize(size);
  67.         automaton_dfs();
  68.     }
  69.     void automaton_dfs(const i32 curr=0){
  70.         ASSERT(extra);
  71.         ASSERT(0<=curr&&curr<size);
  72.         ASSERT(terminal_paths_from[curr]==0);
  73.         ASSERT(substrings_from[curr]==0);
  74.         ASSERT(paths_from[curr]==0);
  75.         terminal_paths_from[curr]=terminal[curr];
  76.         paths_from[curr]=1;
  77.         FORE(edge,next[curr]){
  78.             const i32 other=edge.second;
  79.             UNLESS(paths_from[other]){automaton_dfs(other);}
  80.             terminal_paths_from[curr]+=terminal_paths_from[other];
  81.             substrings_from[curr]+=substrings_from[other];
  82.             paths_from[curr]+=paths_from[other];
  83.         }
  84.         substrings_from[curr]+=terminal_paths_from[curr];
  85.     }
  86.     void complete_states(const i32 last){
  87.         ASSERT(0<=last&&last<size);
  88.         terminal.resize(size);
  89.         for(i32 curr=last;curr!=-1;curr=link[curr]){terminal[curr]=true;}
  90.         inv_link.resize(size);
  91.         for(i32 curr=1;curr<size;++curr){inv_link[link[curr]].push_back(curr);}
  92.     }
  93.     std::pair<i32,i32>run_pattern(const view&pattern)const{
  94.         i32 curr=0,read=0;
  95.         for(
  96.             auto it=pattern.begin();
  97.             it!=pattern.end()&&next[curr].count(*it);
  98.             curr=next[curr].at(*(it++))
  99.         ){++read;}
  100.         return{curr,read};
  101.     }
  102. public:
  103.     suffix_automaton(const view&_text,const bool _extra=false):extra(_extra){
  104.         reserve_memory(SIZE(_text));
  105.         i32 last=0;
  106.         FORE(c,_text){extend(c,last);}
  107.         complete_states(last);
  108.         if(extra){count_paths();}
  109.     }
  110.     const str&peek_text()const{return text;}
  111.     std::pair<str,i32>longest_accepted_prefix(const view&pattern)const{
  112.         const auto[state,read]=run_pattern(pattern);
  113.         const i32 start=firstpos[state]+1-read;
  114.         return{text.substr(start,read),start};
  115.     }
  116.     bool is_suffix(const view&pattern)const{
  117.         if(SIZE(pattern)>SIZE(text)){return false;}
  118.         const auto[state,read]=run_pattern(pattern);
  119.         return terminal[state]&&read==SIZE(pattern);
  120.     }
  121.     bool is_substring(const view&pattern)const{
  122.         if(SIZE(pattern)>SIZE(text)){return false;}
  123.         return run_pattern(pattern).second==SIZE(pattern);
  124.     }
  125.     bool is_prefix(const view&pattern)const{
  126.         if(SIZE(pattern)>SIZE(text)){return false;}
  127.         return std::equal(ALL(pattern),text.begin());
  128.     }
  129.     std::vector<i32>all_borders()const{
  130.         std::vector<i32>borders{0};
  131.         i32 curr=0;
  132.         FORIT(it,text){
  133.             curr=next[curr].at(*it);
  134.             if(terminal[curr]){borders.push_back(I32(it-text.begin())+1);}
  135.         }
  136.         return borders;
  137.     }
  138.     i32 number_occurrences(const view&pattern)const{
  139.         ASSERT(extra);
  140.         if(SIZE(pattern)>SIZE(text)){return 0;}
  141.         const auto[state,read]=run_pattern(pattern);
  142.         return read==SIZE(pattern)?terminal_paths_from[state]:0;
  143.     }
  144.     i32 first_occurrence(const view&pattern)const{
  145.         if(SIZE(pattern)>SIZE(text)){return-1;}
  146.         const i32 m=SIZE(pattern);
  147.         const auto[state,read]=run_pattern(pattern);
  148.         return read==m?firstpos[state]+1-m:-1;
  149.     }
  150.     std::vector<i32>all_occurrences(
  151.         const view&pattern,const bool order=false
  152.     )const{
  153.         if(SIZE(pattern)>SIZE(text)){return{};}
  154.         std::vector<i32>occs;
  155.         const i32 m=SIZE(pattern);
  156.         const auto[node,read]=run_pattern(pattern);
  157.         if(read==m){
  158.             std::stack<i32,std::vector<i32>>st{{node}};
  159.             while(!st.empty()){
  160.                 const i32 curr=st.top();
  161.                 st.pop();
  162.                 occs.push_back(firstpos[curr]+1-m);
  163.                 FORE(child,inv_link[curr]){st.push(child);}
  164.             }
  165.         }
  166.         if(order){
  167.             sort(ALL(occs));
  168.             occs.erase(std::unique(ALL(occs)),occs.end());
  169.         }
  170.         return occs;
  171.     }
  172.     i32 number_suffixes()const{
  173.         ASSERT(extra);
  174.         return terminal_paths_from[0];
  175.     }
  176.     std::pair<str,i32>kth_suffix(i32 k)const{
  177.         ASSERT(extra);
  178.         ASSERT(0<=k&&k<terminal_paths_from[0]);
  179.         i32 start=0,m=0,curr=0;
  180.         while((k-=terminal[curr])>=0){
  181.             FORE(edge,next[curr]){
  182.                 const i32 other=edge.second;
  183.                 const i32 step=terminal_paths_from[other];
  184.                 if(k>=step){k-=step;}
  185.                 else{
  186.                     start=firstpos[curr=other]-(m++);
  187.                     break;
  188.                 }
  189.             }
  190.         }
  191.         return{text.substr(start,m),start};
  192.     }
  193.     i64 number_substrings()const{
  194.         ASSERT(extra);
  195.         return substrings_from[0];
  196.     }
  197.     std::pair<str,i32>kth_substring(i64 k)const{
  198.         ASSERT(extra);
  199.         ASSERT(0<=k&&k<substrings_from[0]);
  200.         i32 start=0,m=0,curr=0;
  201.         while((k-=terminal_paths_from[curr])>=0){
  202.             FORE(edge,next[curr]){
  203.                 const i32 other=edge.second;
  204.                 const i64 step=substrings_from[other];
  205.                 if(k>=step){k-=step;}
  206.                 else{
  207.                     start=firstpos[curr=other]-(m++);
  208.                     break;
  209.                 }
  210.             }
  211.         }
  212.         return{text.substr(start,m),start};
  213.     }
  214.     i64 number_distinct_substrings()const{
  215.         ASSERT(extra);
  216.         return paths_from[0];
  217.     }
  218.     std::pair<str,i32>kth_distinct_substring(i64 k)const{
  219.         ASSERT(extra);
  220.         ASSERT(0<=k&&k<paths_from[0]);
  221.         i32 start=0,m=0,curr=0;
  222.         while((k-=1)>=0){
  223.             FORE(edge,next[curr]){
  224.                 const i32 other=edge.second;
  225.                 const i64 step=paths_from[other];
  226.                 if(k>=step){k-=step;}
  227.                 else{
  228.                     start=firstpos[curr=other]-(m++);
  229.                     break;
  230.                 }
  231.             }
  232.         }
  233.         return{text.substr(start,m),start};
  234.     }
  235.     std::pair<std::pair<str,i32>,i32>longest_repeating_substring()const{
  236.         ASSERT(extra);
  237.         ASSERT(!text.empty());
  238.         i32 start=0,best_len=0,best_occs=SIZE(text)+1;
  239.         for(i32 curr=1;curr<size;++curr){
  240.             const i32 curr_len=len[curr],curr_occs=terminal_paths_from[curr];
  241.             const bool is_better_len=curr_len>best_len&&curr_occs>1;
  242.             const bool is_better_occs=curr_len==best_len&&curr_occs>best_occs;
  243.             if(is_better_len||is_better_occs){
  244.                 start=firstpos[curr]+1-(best_len=curr_len);
  245.                 best_occs=curr_occs;
  246.             }
  247.         }
  248.         return{{text.substr(start,best_len),start},best_occs};
  249.     }
  250.     std::pair<str,i32>longest_common_substring(const view&word)const{
  251.         i32 start=0,curr_len=0,best_len=0,curr=0;
  252.         FORE(c,word){
  253.             while(curr&&!next[curr].count(c)){curr_len=len[curr=link[curr]];}
  254.             if(next[curr].count(c)){curr=next[curr].at(c),++curr_len;}
  255.             if(curr_len>best_len){start=firstpos[curr]+1-(best_len=curr_len);}
  256.         }
  257.         return{text.substr(start,best_len),start};
  258.     }
  259.     static std::pair<str,i32>smallest_cyclic_shift(const view&word){
  260.         suffix_automaton sa;
  261.         const i32 n=SIZE(word);
  262.         sa.reserve_memory(2*n);
  263.         i32 last=0;
  264.         FORE(c,word){sa.extend(c,last);}
  265.         FORE(c,word){sa.extend(c,last);}
  266.         i32 start=0;
  267.         for(i32 curr=0,read=0;read<n;++read){
  268.             curr=sa.next[curr].begin()->second;
  269.             start=sa.firstpos[curr]-read;
  270.         }
  271.         return{sa.text.substr(start,n),start};
  272.     }
  273. };
  274.  
Add Comment
Please, Sign In to add comment