#pragma once
#include"library/sequence/Trie.hpp"template<typenameCHAR,intSIGMA,typenameAbelMonoid=GroupAdd<int>>classAhoCorasick:Trie<CHAR,SIGMA,AbelMonoid>{usingsuper=Trie<CHAR,SIGMA,AbelMonoid>;usingsuper::nodes;usingX=typenameAbelMonoid::value_type;std::vector<int>suffix;boolprepared;public:usingsuper::nxt,super::add,super::node_idx,super::val,super::prefix_prod,super::suffix_prod,super::query,super::restore,super::prod,super::size;AhoCorasick():prepared(false){}boolis_prepared()const{returnprepared;}voidbuild(){assert(!prepared);prepared=true;suffix.resize(nodes.size());std::queue<int>que;que.push(0);while(que.size()){intnow=que.front();que.pop();for(inti=0;i<SIGMA;i++){int&nxt_id=nodes[now].nxt[i];if(~nxt_id){suffix[nxt_id]=(now?nodes[suffix[now]].nxt[i]:0);AbelMonoid::Rchop(val(nxt_id),val(suffix[nxt_id]));que.push(nxt_id);}elsenxt_id=(now?nodes[suffix[now]].nxt[i]:0);}}}Xpath_prod(conststd::vector<CHAR>&v){assert(prepared);Xres=AbelMonoid::unit();intnow=0;for(constCHAR&a:v){now=nxt(now,a);AbelMonoid::Rchop(res,val(now));}returnres;}};
#line 2 "library/algebra/group/Add.hpp"
template<typenameX>structGroupAdd{usingvalue_type=X;staticconstexprXop(constX&x,constX&y)noexcept{returnx+y;}staticconstexprvoidRchop(X&x,constX&y){x+=y;}staticconstexprvoidLchop(constX&x,X&y){y+=x;}staticconstexprXinverse(constX&x)noexcept{return-x;}staticconstexprXpower(constX&x,longlongn)noexcept{returnX(n)*x;}staticconstexprXunit(){returnX(0);}staticconstexprboolcommute=true;};#line 2 "library/sequence/ForString.hpp"
template<charMARGIN>structForString{staticconstexprcharchange(charc){returnc-MARGIN;}staticconstexprcharrestore(chara){returna+MARGIN;}staticstd::vector<char>change(conststd::string&s){std::vector<char>v(s.size());for(inti=0;i<s.size();i++)v[i]=change(s[i]);returnv;}staticstd::stringrestore(conststd::vector<char>&v){std::strings(v.size(),'#');for(inti=0;i<v.size();i++)s[i]=restore(v[i]);returns;}};structFSAa{staticconstexprcharchange(charc){returnc<='Z'?c-'A':26+c-'a';}staticconstexprcharrestore(chara){returna<26?'A':a-26+'a';}staticstd::vector<char>change(conststd::string&s){std::vector<char>v(s.size());for(inti=0;i<s.size();i++)v[i]=change(s[i]);returnv;}staticstd::stringrestore(conststd::vector<char>&v){std::strings(v.size(),'#');for(inti=0;i<v.size();i++)s[i]=restore(v[i]);returns;}};usingFSA=ForString<'A'>;usingFSa=ForString<'a'>;usingFS0=ForString<'0'>;#ifdef STR
#define STRA(s) \
STR(s##tomato); \
auto s = FSA::change(s##tomato);
#define STRa(s) \
STR(s##tomato); \
auto s = FSa::change(s##tomato);
#define STR0(s) \
STR(s##tomato); \
auto s = FS0::change(s##tomato);
#endif
#line 4 "library/sequence/Trie.hpp"
template<typenameCHAR,intSIGMA,typenameAbelMonoid=GroupAdd<int>>classTrie{protected:usingX=typenameAbelMonoid::value_type;structNode{std::array<int,SIGMA>nxt;intpre;Xval,suffix_val;// suffix_val は自身を含まないNode(intpre):pre(pre),val(AbelMonoid::unit()),suffix_val(AbelMonoid::unit()){std::ranges::fill(nxt,-1);}};std::vector<Node>nodes;public:Trie():nodes(1,Node(-1)){}int&nxt(intnow,constCHAR&a){returnnodes[now].nxt[a];}constint&nxt(intnow,constCHAR&a)const{returnnodes[now].nxt[a];}intadd(conststd::vector<CHAR>&v,Xx=1){intnow=0;for(constCHAR&a:v){assert(0<=aanda<SIGMA);if(!~nxt(now,a)){nxt(now,a)=nodes.size();nodes.emplace_back(now);}AbelMonoid::Rchop(nodes[now].suffix_val,x);now=nxt(now,a);}AbelMonoid::Rchop(nodes[now].val,x);returnnow;}intnode_idx(conststd::vector<CHAR>&v)const{// s の Node を返す 追加されて無ければ -1intnow=0;for(constCHAR&a:v){if(!~nxt(now,a))return-1;now=nxt(now,a);}returnnow;}Xval(conststd::vector<CHAR>&v){intid=node_idx(v);return(~id?nodes[id].val:AbelMonoid::unit());}X&val(intnode_id){returnnodes[node_id].val;}// vは含まないXprefix_prod(conststd::vector<CHAR>&v){intnow=0;Xsum=AbelMonoid::unit();for(constCHAR&a:v){if(!~nxt(now,a))break;AbelMonoid::Rchop(sum,nodes[now].val);now=nxt(now,a);}returnsum;}// vは含まないXsuffix_prod(conststd::vector<CHAR>&v)const{intid=node_idx(v);return(~id?nodes[id].suffix_val:AbelMonoid::unit());}std::vector<CHAR>restore(intnode_id){assert(0<=node_idandnode_id<nodes.size());std::vector<CHAR>res;while(~nodes[node_id].pre){intpre=nodes[node_id].pre;for(intj=0;j<SIGMA;j++)if(nxt(pre,j)==node_id){res.push_back(j);break;}node_id=pre;}std::ranges::reverse(res);returnres;}Xprod()const{returnnodes[0].suffix_val;}intsize()const{returnnodes.size();}template<typenameF>voidquery(conststd::vector<CHAR>&v,constF&f,intl=0,intr=-1){if(r<0)r=v.size();intnow=0;for(inti=l;i<r;i++){now=nxt(now,v[i]);if(~now)f(now);elsebreak;}}};#line 3 "library/sequence/AhoCorasick.hpp"
template<typenameCHAR,intSIGMA,typenameAbelMonoid=GroupAdd<int>>classAhoCorasick:Trie<CHAR,SIGMA,AbelMonoid>{usingsuper=Trie<CHAR,SIGMA,AbelMonoid>;usingsuper::nodes;usingX=typenameAbelMonoid::value_type;std::vector<int>suffix;boolprepared;public:usingsuper::nxt,super::add,super::node_idx,super::val,super::prefix_prod,super::suffix_prod,super::query,super::restore,super::prod,super::size;AhoCorasick():prepared(false){}boolis_prepared()const{returnprepared;}voidbuild(){assert(!prepared);prepared=true;suffix.resize(nodes.size());std::queue<int>que;que.push(0);while(que.size()){intnow=que.front();que.pop();for(inti=0;i<SIGMA;i++){int&nxt_id=nodes[now].nxt[i];if(~nxt_id){suffix[nxt_id]=(now?nodes[suffix[now]].nxt[i]:0);AbelMonoid::Rchop(val(nxt_id),val(suffix[nxt_id]));que.push(nxt_id);}elsenxt_id=(now?nodes[suffix[now]].nxt[i]:0);}}}Xpath_prod(conststd::vector<CHAR>&v){assert(prepared);Xres=AbelMonoid::unit();intnow=0;for(constCHAR&a:v){now=nxt(now,a);AbelMonoid::Rchop(res,val(now));}returnres;}};