SAM板子(自用)

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

#define ll long long

struct SAM
{
	string s;
	int size, last;
	vector<int>len, link,siz,t,AN;
	vector<vector<int>> to;
	//字符串长度,字符集大小
	void Init(int strlen, int chSize)
	{
		size = 1;
		last = 1;
		len.resize(strlen << 1,0);
		AN.resize(strlen << 1,0);
		t.resize(strlen << 1,0);
		link.resize(strlen << 1,0);
		siz.resize(strlen << 1,0);
		to.resize(strlen << 1,vector<int>(chSize,0));
	}
	
	//清空
	void clear()
	{
		to.clear();
		len.clear();
		link.clear();
	}
	
	//为当前的SAM增加一个字符C
	void extend(int c)
	{
		int p,cur = ++size;
		len[cur] = len[last] + 1;
		siz[cur] = 1;//表示某个子串出现次数
		//情况1
		for(p = last; p && !to[p][c]; p = link[p])
		{
			to[p][c] = cur;
		}
		if(!p) link[cur] = 1;
		else
		{
			int q = to[p][c];
			//情况2 - A
			if(len[q] == len[p] + 1) link[cur] = q;
			else
			{
				//情况2 - B
				int cl = ++size;
				len[cl] = len[p] + 1;
				to[cl] = to[q],link[cl] = link[q];
				while(p && to[p][c] == q)
				{
					to[p][c] = cl;
					p = link[p];
				}
				link[cur] = link[q] = cl;
			}
		}
		last = cur;
	}
	
	void TOPU()
	{
		for(int i = 1; i <= size; i ++ ) t[len[i]] ++;
		for(int i = 1; i <= size; i ++ ) t[i] += t[i - 1];
		for(int i = 1; i <= size; i ++ ) AN[t[len[i]]--] = i;
		for(int i = size; i >= 1; i -- ) siz[link[AN[i]]] += siz[AN[i]];
	}
	
	int find(string& ok)
	{
		if(ok.length() > s.length()) return 0;
		int now = 1;
		for(int i = 0; i < (int)ok.length(); i ++ )
		{
			if(to[now][ok[i] - 'a' + 1]) now = to[now][ok[i] - 'a' + 1];
			else return 0;
		}
		return 1;
	}
	
	void build()
	{
		cin >> s;
		Init(s.length(),30);
		ll ans = 0;
		for(int i = 0; i < (int)s.length(); i ++ ) extend(s[i] - 'a' + 1);
		TOPU();
		for(int i = 1; i <= size; i ++ )
		{
			if(siz[i] > 1)
			{
				ans = max(ans,1LL * siz[i] * len[i]);
			}
		}
		cout << ans << '\n';
	}
	
	
}sam;

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	sam.build();
	return 0;
}

广义SAM

//if(to[last][c])
//{
//	int q = to[last][c];
//	int p = last;
//	if(len[p] + 1 == len[q])
//	{
//		last = q;
//		return;
//	}
//	int cl = ++size;
//	link[cl] = link[q];
//	link[q] = cl;
//	len[cl] = len[p] + 1;
//	to[cl] = to[q];
//	while(p && to[p][c] == q)
//	{
//		to[p][c] = cl;
//		p = link[p];
//	}
//	last = cl;
//	return;
//}

Tire树版

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

#define ll long long

const int M = 2e6 + 10;



struct Tire
{
	int v[11];
	int ch;
	int fa;
	int ls;
};

struct SAM
{
	int idx = 1;
	Tire tr[M];
	// string s;
	int col[M];
	int size,last;
	vector<int>len, link,pos,dad,deg;
	vector<int>e[M];
	vector<vector<int>> to;
	//字符串长度,字符集大小
	void Init(int strlen, int chSize)
	{
		last = 1;
		size = 1;
		len.resize(M,0);
		link.resize(M,0);
		deg.resize(strlen + 1,0);
		to.resize(M,vector<int>(chSize + 1,0));
	}
	
	//清空
	void clear()
	{
		to.clear();
		len.clear();
		link.clear();
	}
	
	//为当前的SAM增加一个字符C
	void extend(int c)
	{
		int p,cur = ++size;
		len[cur] = len[last] + 1;
		//情况1
		for(p = last; p && !to[p][c]; p = link[p])
		{
			to[p][c] = cur;
		}
		if(!p) link[cur] = 1;
		else
		{
			int q = to[p][c];
			//情况2 - A
			if(len[q] == len[p] + 1) link[cur] = q;
			else
			{
				//情况2 - B
				int cl = ++size;
				len[cl] = len[p] + 1;
				to[cl] = to[q],link[cl] = link[q];
				while(p && to[p][c] == q)
				{
					to[p][c] = cl;
					p = link[p];
				}
				link[cur] = link[q] = cl;
			}
		}
		last = cur;
	}
	
	void bfs()
	{
		queue<int>q;
		for(int i = 1; i <= 10; i ++ ) if(tr[1].v[i]) q.push(tr[1].v[i]);
		tr[1].ls = 1;
		while(q.size())
		{
			int u = q.front();
			q.pop();
			last = tr[tr[u].fa].ls;
			extend(tr[u].ch);
			tr[u].ls = last;
			for(int i = 1; i <= 10; i ++ ) if(tr[u].v[i]) q.push(tr[u].v[i]);
		}
	}
	
	int insert(int p,int c)
	{
		if(!tr[p].v[c])
		{
			tr[p].v[c] = ++idx;
			tr[idx].fa = p;
			tr[idx].ch = c;
		}
		return tr[p].v[c];
	}
	
	void dfs(int u,int dad,int dad_pos)
	{
		int pos = insert(dad_pos,col[u]);
		for(int v : e[u]) if(v != dad) dfs(v,u,pos);
	}
	
	void build()
	{
		int n,c;
		cin >> n >> c;
		Init(n,c);
		for(int i = 1; i <= n; i ++ )
		{
			cin >> col[i];
			col[i] ++;
		}
		
		for(int i = 1; i < n; i ++ )
		{
			int u,v;
			cin >> u >> v;
			e[u].push_back(v);
			e[v].push_back(u);
			deg[u] ++;
			deg[v] ++;
		}
		for(int i = 1; i <= n; i ++ ) if(deg[i] == 1) dfs(i,0,1);//找出所有的串
//		建立Tire树
		
		bfs();
		ll ans = 0;
		for(int i = 1; i <= size; i ++ ) ans += len[i] - len[link[i]];
		cout << ans << '\n';
	}
	
	
}sam;

int main()
{
	sam.build();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值