【数据结构】广义 SAM 简述

广义后缀自动机简述

不了解后缀自动机的可以看看:

https://www.cnblogs.com/Tenshi/p/16408718.html

在字典树的基础上建立广义后缀自动机。

建立

对若干模式串,先插入字典树中。

注意到对字典树进行 \(\texttt{bfs}\) 的时候,对应的状态的 \(len\) 是不降的(状态和 \(len\) 的概念参考后缀自动机)。

所以我们按照这个顺序将字符一次插入到后缀自动机中,并相应地建立 \(link\)

而插入的过程可以按照普通的 SAM 的插入操作修改而来。

模板题以及代码实现

https://www.luogu.com.cn/problem/P6139

// Problem: P6139 【模板】广义后缀自动机(广义 SAM)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P6139
// Memory Limit: 500 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()

#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=2e6+5, CHR=26; 

int n;

struct GSAM{
	struct Node{
		int fa, len;
		int ch[CHR];
	}node[N];
	
	int tot;
	
	void init(){
		tot=1;
		node[tot].fa=0;
	}
	
	void insert(string &s){
		int u=1;
		for(auto &i: s){
			int &go=node[u].ch[i-'a'];
			if(!go) go=++tot;
			u=go;
		}
	}
	
	int ins(int last, int c){
		int cur=node[last].ch[c];
		if(node[cur].len) return cur;
		node[cur].len=node[last].len+1;
		int p=node[last].fa;
		
		for(; p && !node[p].ch[c]; p=node[p].fa) node[p].ch[c]=cur;
		if(!p) return node[cur].fa=1, cur;
		
		int q=node[p].ch[c];
		if(node[p].len+1==node[q].len) return node[cur].fa=q, cur;
		
		int nq=++tot;
		rep(i,0,CHR-1) node[nq].ch[i]=(node[node[q].ch[i]].len==0? 0: node[q].ch[i]);
		node[nq].len=node[p].len+1;
		for(; p && node[p].ch[c]==q; ) node[p].ch[c]=nq, p=node[p].fa;
		node[nq].fa=node[q].fa;
		node[cur].fa=node[q].fa=nq;
		return cur;
	}
	
	void build(){
		queue<pii> q;
		rep(i,0,CHR-1) if(node[1].ch[i]) q.push({1, i});
		while(q.size()){
			auto [x, y]=q.front(); q.pop();
			int last=ins(x, y);
			rep(i,0,CHR-1) if(node[last].ch[i]) q.push({last, i});
		}
	}
	
	void solve(){
		ll res=0;
		rep(i,2,tot) res+=node[i].len-node[node[i].fa].len;
		cout<<res<<endl;
	}
}gsam;

int main(){
	cin>>n;
	gsam.init();
	rep(i,1,n){
		string s; cin>>s;
		gsam.insert(s);
	}
	gsam.build();
	gsam.solve();
	
	return 0;
}
posted @ 2022-06-24 23:54  HinanawiTenshi  阅读(106)  评论(0编辑  收藏  举报