后缀树

变量

  • int tot\texttt{int tot}:节点个数。
  • int tpos\texttt{int tpos}:字符个数。
  • int now\texttt{int now}:现在走到了哪个点。
  • int rem\texttt{int rem}:最长隐式后缀长度。
  • int inf\texttt{int inf}:正无穷。
  • int s[i]\texttt{int s[i]}:插入的字符。
  • Node a[p]\texttt{Node a[p]}:节点 pp 的信息。
  • int a[p].link\texttt{int a[p].link}:节点 pplink\text{link} 链接,指向从根到当前节点的字符串的最大后缀所在的点。
  • int a[p].st\texttt{int a[p].st}:节点 pp 代表的一段字符串的起点位置。
  • int a[p].len\texttt{int a[p].len}:节点 pp 代表的一段字符串的长度。
  • int a[p].len\texttt{int a[p].len}:节点 pp 代表的子串集合中最长的长度。
  • int a[p].ch[c]\texttt{int a[p].ch[c]}:节点 pp 加上字符 cc 后的儿子。

函数

  • SufTree()\texttt{SufTree()}:初始化。
  • int make(int st,int len)\texttt{int make(int st,int len)}:新建起点为 stst 长度为 lenlen 的节点。
  • void extend(int x)\texttt{void extend(int x)}:在后缀树的字符串末尾加入字符 xx

代码

struct SufTree{
	int tot,tpos,now,rem,inf;
	int s[N];
	struct Node{
		int link,st,len,ch[27];
	}a[N<<1];
	SufTree(){
		tot=now=1,tpos=rem=0;
		a[0].len=inf=1e9;
	}
	int make(int st,int len){
		a[++tot].link=1;a[tot].st=st;
		a[tot].len=len;return tot;
	}
	void extend(int x){
		s[++tpos]=x;rem++;
		for(int lst=1;rem;){
			while(rem>a[a[now].ch[s[tpos-rem+1]]].len)
				rem-=a[now=a[now].ch[s[tpos-rem+1]]].len;
			int p=a[now].ch[s[tpos-rem+1]],q;
			int c=s[a[p].st+rem-1];
			if(!p||x==c){
				a[lst].link=now;lst=now;
				if(!p)a[now].ch[s[tpos-rem+1]]=make(tpos,inf);
				else break;
			}
			else{
				q=make(a[p].st,rem-1);
				a[q].ch[c]=p;
				a[q].ch[x]=make(tpos,inf);
				a[p].st+=rem-1;a[p].len-=rem-1;
				a[lst].link=a[now].ch[s[tpos-rem+1]]=q;
				lst=q;
			}
			if(now==1)rem--;else now=a[now].link;
		}
	}
}st;
posted @ 2024-02-22 20:06  luckydrawbox  阅读(13)  评论(0)    收藏  举报  来源