字符串模板

AC自动机

点击查看代码
int ed[N];
const char CH = '0';
const int H = 10;
struct AC {
	struct Node {
		int son[H];  // 子结点
		int fail;     // fail 指针
		int cnt;
		long long sum;

		void init() {  // 结点初始化
			memset(son, 0, sizeof(son));
			fail = cnt = 0;
			sum = 0;
		}
	};
	vector<Node>tr;
	int tot;  // 结点总数

	void init() {
		tot = 0;
		tr.clear();
		tr.emplace_back();
		tr[0].init();
	}

	void insert(string &s) {
		int u = 0;
		int L = s.length();
		for (int i = 0; i < L; i++) {
			if (!tr[u].son[s[i] - CH]) {
				tr[u].son[s[i] - CH] = ++tot;
				tr.emplace_back();
				tr[tr[u].son[s[i] - CH]].init();
			}
			u = tr[u].son[s[i] - CH];                                // 从下一个结点继续
		}
		ed[u] = 1;
		tr[u].cnt++;
	}

	void build() {
		queue<int> q;
		for (int i = 0; i < H; i++)
			if (tr[0].son[i]) {
				tr[tr[0].son[i]].sum = tr[tr[0].son[i]].cnt;
				q.push(tr[0].son[i]);
			}
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			for (int i = 0; i < H; i++) {
				if (tr[u].son[i]) {                               // 存在对应子结点
					tr[tr[u].son[i]].fail = tr[tr[u].fail].son[i];  // 只用跳一次 fail 指针
					ed[tr[u].son[i]] |= ed[tr[tr[u].son[i]].fail];
					tr[tr[u].son[i]].sum = tr[tr[u].son[i]].cnt + tr[tr[tr[u].son[i]].fail].sum;
					q.push(tr[u].son[i]);                           // 并加入队列
				} else
					tr[u].son[i] =
					    tr[tr[u].fail]
					    .son[i];  // 将不存在的字典树的状态链接到了失配指针的对应状态
			}
		}
	}

	long long query(string &t) {
		int u = 0;
		long long ans = 0;
		int L = t.length();
		for (int i = 0; i < L; i++) {
			u = tr[u].son[t[i] - CH];  // 转移
			ans += tr[u].sum;
		}
		return ans;
	}
};

后缀数组 和 两子串最长公共前缀

点击查看代码
int n,m,p;
int sa[N], rk[N << 1], oldrk[N << 1], id[N], cnt[N];
int height[N];
constexpr int logN = 16;
int f[logN + 1][N],Logn[N];
void init(string &s){
	m = 128;
	memset(cnt, 0, sizeof(cnt));
	for (int i = 1; i <= n; i++) cnt[rk[i] = s[i]]++;
	for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
	for (int i = n; i >= 1; i--) sa[cnt[rk[i]]--] = i;
	
	for (int w = 1;; w <<= 1, m = p) {  // m = p 即为值域优化
		int cur = 0;
		for (int i = n - w + 1; i <= n; i++) id[++cur] = i;
		for (int i = 1; i <= n; i++)
			if (sa[i] > w) id[++cur] = sa[i] - w;
		
		memset(cnt, 0, sizeof(cnt));
		for (int i = 1; i <= n; i++) cnt[rk[i]]++;
		for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
		for (int i = n; i >= 1; i--) sa[cnt[rk[id[i]]]--] = id[i];
		
		p = 0;
		memcpy(oldrk, rk, sizeof(oldrk));
		for (int i = 1; i <= n; i++) {
			if (oldrk[sa[i]] == oldrk[sa[i - 1]] &&
				oldrk[sa[i] + w] == oldrk[sa[i - 1] + w])
				rk[sa[i]] = p;
			else
				rk[sa[i]] = ++p;
		}
		
		if (p == n) break;  // p = n 时无需再排序
	}
	for (int i = 1, k = 0; i <= n; ++i) {
		if (rk[i] == 0) continue;
		if (k) --k;
		while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
		height[rk[i]] = k;
	}
	Logn[2] = 1;
	for (int i = 3; i < N; i++) {
		Logn[i] = Logn[i / 2] + 1;
	}
	for (int i = 1; i <= n; i++){
		f[0][i]=height[i];
	}
	for (int j = 1; j <= logN; j++){
		for (int i = 1; i + (1 << j) - 1 <= n; i++){
			f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
		}
	}
}


int get(int x,int y){
	x=rk[x];
	y=rk[y];
	if(x>y)swap(x,y);
	x++;
	int s = Logn[y - x + 1];
	return min(f[s][x], f[s][y - (1 << s) + 1]);
}
posted @ 2026-09-09 19:34  ptlks  阅读(10)  评论(0)    收藏  举报