【BZOJ2780】【SPOJ8093】Sevenk Love Oimaster

本文介绍了一种基于后缀自动机的数据结构实现,并详细展示了其构建过程及如何通过该结构解决字符串查询问题。文章提供了完整的源代码,并通过一个具体的例子解释了如何插入字符串、查询子串出现情况及维护自动机的状态。

【题目链接】

【思路要点】

  • 补档博客,无题解。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	200005
#define MAXL	360005
struct Suffix_Automaton {
	map <char, int> child[MAXN];
	int father[MAXN], depth[MAXN];
	int root, size, last, timer;
	vector <int> colour[MAXN], a[MAXN];
	int num[MAXN], right[MAXN], home[MAXN];
	int new_node(int dep) {
		depth[size] = dep;
		father[size] = 0;
		child[size].clear();
		colour[size].clear();
		a[size].clear();
		num[size] = right[size] = 0;
		return size++;
	}
	void init() {
		size = 0;
		root = last = new_node(0);
	}
	void Extend(char ch, int col) {
		int np = child[last][ch];
		if (np) {
			if (depth[np] == depth[last] + 1)  {
				colour[np].push_back(col);
				last = np;
			} else {
				int nq = new_node(depth[last] + 1);
				father[nq] = father[np];
				father[np] = nq;
				child[nq] = child[np];
				for (int p = last; child[p][ch] == np; p = father[p])
					child[p][ch] = nq;
				colour[nq].push_back(col);
				last = nq;
			}
		} else {
			int np = new_node(depth[last] + 1);
			int p = last;
			for (; child[p][ch] == 0; p = father[p])
				child[p][ch] = np;
			if (child[p][ch] == np) {
				colour[np].push_back(col);
				last = np;
				return;
			}
			int q = child[p][ch];
			if (depth[q] == depth[p] + 1) {
				father[np] = q;
				colour[np].push_back(col);
				last = np;
				return;
			} else {
				int nq = new_node(depth[p] + 1);
				father[nq] = father[q];
				father[np] = father[q] = nq;
				child[nq] = child[q];
				for (; child[p][ch] == q; p = father[p])
					child[p][ch] = nq;
				colour[np].push_back(col);
				last = np;
			}
		}
	}
	void insert(char *s, int col) {
		int len = strlen(s + 1);
		last = root;
		for (int i = 1; i <= len; i++)
			Extend(s[i], col);
	}
	int visit(char *s) {
		int pos = root, len = strlen(s + 1);
		for (int i = 1; i <= len; i++) {
			pos = child[pos][s[i]];
			if (!pos) return -1;
		}
		return pos;
	}
	void work(int pos) {
		num[pos] = ++timer;
		home[timer] = pos;
		for (unsigned i = 0; i < a[pos].size(); i++)
			work(a[pos][i]);
		right[pos] = timer;
	}
	void build() {
		for (int i = 1; i < size; i++)
			a[father[i]].push_back(i);
		work(0);
	}
} SAM;
struct Query {
	int home, l, r;
} Q[MAXN];
bool cmp(Query x, Query y) {
	return x.r < y.r;
}
int n, q, ans[MAXN];
int Last[MAXN], sum[MAXN];
char s[MAXL];
int query(int x) {
	int ans = 0;
	for (int i = x; i > 0; i -= i & -i)
		ans += sum[i];
	return ans;
}
void change(int x, int d) {
	for (int i = x; i <= SAM.timer; i += i & -i)
		sum[i] += d;
}
int main() {
	scanf("%d%d", &n, &q);
	SAM.init();
	for (int i = 1; i <= n; i++) {
		scanf("\n%s", s + 1);
		SAM.insert(s, i);
	}
	SAM.build();
	for (int i = 1; i <= q; i++) {
		scanf("\n%s", s + 1);
		int tmp = SAM.visit(s);
		Q[i].home = i;
		if (tmp != -1) {
			Q[i].l = SAM.num[tmp];
			Q[i].r = SAM.right[tmp];
		} else Q[i].l = Q[i].r = 0;
	}
	sort(Q + 1, Q + q + 1, cmp);
	int last = 0;
	for (int i = 1; i <= q; i++) {
		while (last < Q[i].r) {
			last++;
			int now = SAM.home[last];
			for (unsigned j = 0; j < SAM.colour[now].size(); j++) {
				int tmp = SAM.colour[now][j];
				if (Last[tmp]) change(Last[tmp], -1);
				change(last, 1);
				Last[tmp] = last;
			}
		}
		ans[Q[i].home] = query(Q[i].r) - query(Q[i].l - 1);
	}
	for (int i = 1; i <= q; i++)
		printf("%d\n", ans[i]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值