export class Trie{constructor(){this._size,this._root=0,this._edges,this._isWord,this._wordsInSubtree,this._freeNodes,this.clear()}add(s){let t=this._root;++this._wordsInSubtree[this._root];for(let e=0;e<s.length;++e){const r=s[e];let i=this._edges[t][r];i||(this._freeNodes.length?i=this._freeNodes.pop():(i=this._size++,this._isWord.push(!1),this._wordsInSubtree.push(0),this._edges.push({__proto__:null})),this._edges[t][r]=i),++this._wordsInSubtree[i],t=i}this._isWord[t]=!0}remove(s){if(!this.has(s))return!1;let t=this._root;--this._wordsInSubtree[this._root];for(let e=0;e<s.length;++e){const r=s[e],i=this._edges[t][r];--this._wordsInSubtree[i]||(delete this._edges[t][r],this._freeNodes.push(i)),t=i}return this._isWord[t]=!1,!0}has(s){let t=this._root;for(let e=0;e<s.length;++e)if(t=this._edges[t][s[e]],!t)return!1;return this._isWord[t]}words(s){s=s||"";let t=this._root;for(let r=0;r<s.length;++r)if(t=this._edges[t][s[r]],!t)return[];const e=[];return this._dfs(t,s,e),e}_dfs(s,t,e){this._isWord[s]&&e.push(t);const r=this._edges[s];for(const i in r)this._dfs(r[i],t+i,e)}longestPrefix(s,t){let e=this._root,r=0;for(let i=0;i<s.length&&(e=this._edges[e][s[i]],e);++i)t&&!this._isWord[e]||(r=i+1);return s.substring(0,r)}clear(){this._size=1,this._root=0,this._edges=[{__proto__:null}],this._isWord=[!1],this._wordsInSubtree=[0],this._freeNodes=[]}}