【BZOJ1396】识别子串

【题目链接】

【双倍经验链接】

【思路要点】

  • 补档博客,无题解。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	200005
struct Segment_Tree {
	int lc[MAXN], rc[MAXN], ans[MAXN];
	int root, size, n, INF;
	int new_node() {
		lc[size] = rc[size] = ans[size];
		return size++;
	}
	void build(int root, int l, int r) {
		ans[root] = INF;
		if (l == r) return;
		int mid = (l + r) / 2;
		lc[root] = new_node();
		build(lc[root], l, mid);
		rc[root] = new_node();
		build(rc[root], mid + 1, r);
	}
	void init(int x) {
		size = 0; n = x; INF = 1e9;
		root = new_node();
		build(root, 1, n);
	}
	void pushdown(int pos) {
		ans[lc[pos]] = min(ans[lc[pos]], ans[pos]);
		ans[rc[pos]] = min(ans[rc[pos]], ans[pos]);
		ans[pos] = INF;
	}
	void modify(int pos, int l, int r, int ql, int qr, int v) {
		if (ql == l && r == qr) {
			ans[pos] = min(ans[pos], v);
			return;
		}
		int mid = (l + r) / 2;
		if (ql <= mid) modify(lc[pos], l, mid, ql, min(qr, mid), v);
		if (qr >= mid + 1) modify(rc[pos], mid + 1, r, max(mid + 1, ql), qr, v);
	}
	void modify(int l, int r, int v) {
		if (l > r) return;
		modify(root, 1, n, l, r, v);
	}
	int query(int pos, int l, int r, int x) {
		if (l == r) return ans[pos];
		pushdown(pos);
		int mid = (l + r) / 2;
		if (x <= mid) return query(lc[pos], l, mid, x);
		else return query(rc[pos], mid + 1, r, x);
	}
	int query(int x) {
		return query(root, 1, n, x);
	}
} A, B;
struct Suffix_Automaton {
	int child[MAXN][26];
	int father[MAXN], depth[MAXN];
	vector <int> a[MAXN];
	int cnt[MAXN], end[MAXN];
	int root, size, last, len;
	int new_node(int dep) {
		memset(child[size], 0, sizeof(child[size]));
		father[size] = 0;
		depth[size] = dep;
		a[size].clear();
		cnt[size] = 0;
		return size++;
	}
	void init() {
		size = 0;
		root = last = new_node(0);
	}
	void Extend(int ch, int pos) {
		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) father[np] = root;
		else {
			int q = child[p][ch];
			if (depth[p] + 1 == depth[q]) father[np] = q;
			else {
				int nq = new_node(depth[p] + 1);
				father[nq] = father[q];
				father[q] = father[np] = nq;
				memcpy(child[nq], child[q], sizeof(child[q]));
				for (; child[p][ch] == q; p = father[p])
					child[p][ch] = nq;
			}
		}
		last = np;
		cnt[np] = 1;
		end[np] = pos;
	}
	void insert(char *s) {
		len = strlen(s + 1);
		for (int i = 1; i <= len; i++)
			Extend(s[i] - 'a', len - i + 1);
	}
	void maintain(int pos) {
		if (pos == root) return;
		int fa = father[pos];
		A.modify(end[pos], end[pos] + depth[fa], depth[fa] + 1);
		B.modify(end[pos] + depth[fa], len, 1 - end[pos]);
	}
	void work(int pos) {
		if (a[pos].size() == 1) {
			work(a[pos][0]);
			cnt[pos] += cnt[a[pos][0]];
			end[pos] = end[a[pos][0]];
			if (cnt[pos] == 1) maintain(pos);
			else end[pos] = 0;
		} else {
			for (unsigned i = 0; i < a[pos].size(); i++) {
				work(a[pos][i]);
				cnt[pos] += cnt[a[pos][i]];
				end[pos] = end[a[pos][i]];
			}
			if (cnt[pos] == 1) maintain(pos);
			else end[pos] = 0;
		}
	}
	void build() {
		for (int i = 1; i < size; i++)
			a[father[i]].push_back(i);
		work(root);
	}
} SAM;
char s[MAXN];
int main() {
	scanf("%s", s + 1);
	SAM.init();
	for (int i = 1, j = strlen(s + 1); i < j; i++, j--)
		swap(s[i], s[j]);
	SAM.insert(s);
	int n = strlen(s + 1);
	A.init(n);
	B.init(n);
	SAM.build();
	for (int i = 1; i <= n; i++)
		printf("%d\n", min(A.query(i), B.query(i) + i));
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值