BZOJ 1396 识别子串

题面

Description

Input

一行,一个由小写字母组成的字符串S,长度不超过10^5

Output

L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

Sample Input

agoodcookcooksgoodfood

Sample Output

1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4

题解

后缀自动机跑一遍, 得到的Parent Tree上, 存在每个节点的\(size\)即为它所代表的子串的出现次数.
找到每一个叶子节点, 得到它所代表的最短字符串\(str[L .. R]\), 开两棵线段树, 一棵更新\([L .. R]\)区间中的位置的最短识别子串长度, 另一颗更新\([0, L - 1]\)位置上的最短识别子串.

#include <cstdio>
#include <cstring>
#include <algorithm>

const int LEN = (int)1e5;

struct segmentTree
{
	int a[LEN << 2];
	
	inline segmentTree()
	{
		memset(a, 127, sizeof(a));
	}

	void modify(int u, int curL, int curR, int L, int R, int w)
	{
		if(curL >= L && curR <= R)
		{
			a[u] = std::min(a[u], w);
			return;
		}
		int mid = curL + curR >> 1;
		if(L <= mid)
			modify(u << 1, curL, mid, L, R, w);
		if(R > mid)
			modify(u << 1 | 1, mid + 1, curR, L, R, w);
	}

	void modify(int L, int R, int w)
	{
		modify(1, 0, LEN - 1, L, R, w);
	}

	int query(int u, int L, int R, int pos)
	{
		if(L == R)
			return a[u];
		int mid = L + R >> 1;
		if(pos <= mid)
			return std::min(a[u], query(u << 1, L, mid, pos));
		else
			return std::min(a[u], query(u << 1 | 1, mid + 1, R, pos));
	}

	inline int query(int pos)
	{
		return query(1, 0, LEN - 1, pos);
	}
}A, B;

struct suffixAutomaton
{
	struct state
	{
		state *suc[26], *pre;
		int len, sz, tg;

		inline state()
		{
			sz = 1, tg = 0;
			for(int i = 0; i < 26; ++ i)
				suc[i] = NULL;
		}
	};

	state *rt, *lst;

	inline void insert(int c)
	{
		state *u = new state;
		u->len = lst->len + 1;
		for(; lst != NULL && lst->suc[c] == NULL; lst->suc[c] = u, lst = lst->pre);
		if(lst == NULL)
			u->pre = rt;
		else
		{
			state *p = lst->suc[c];
			if(p->len == lst->len + 1)
				u->pre = p;
			else
			{
				state *q = new state;
				*q = *p;
				q->len = lst->len + 1;
				p->pre = u->pre = q;
				for(; lst != NULL && lst->suc[c] == p; lst->suc[c] = q, lst = lst->pre);
			}
		}
		lst = u;
	}

	inline void build(char *str, int len)
	{
		lst = rt = new state;
		rt->len = 0, rt->pre = NULL;
		for(int i = 0; i < len; ++ i)
			insert(str[i] - 'a');
	}

	void getSize(state *u)
	{
		u->tg = 1;
		if(u->pre != NULL)
			++ u->pre->sz;
		for(int i = 0; i < 26; ++ i)
			if(u->suc[i] != NULL && ! u->suc[i]->tg)
				getSize(u->suc[i]);
	}

	void DFS(state *u)
	{
		u->tg = 2;
		if(u->sz == 1)
		{
			A.modify(u->len - u->pre->len - 1, u->len - 1, u->pre->len + 1);
			if(u->len - u->pre->len - 1 > 0)
				B.modify(0, u->len - u->pre->len - 2, u->len - 1);
		}
		for(int i = 0; i < 26; ++ i)
			if(u->suc[i] != NULL && u->suc[i]->tg == 1)
				DFS(u->suc[i]);
	}

	inline void work()
	{
		getSize(rt);
		DFS(rt);
	}
}SAM;

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("BZOJ1396.in", "r", stdin);
	#endif
	static char str[LEN];
	scanf("%s", str);
	int len = strlen(str);
	SAM.build(str, len);
	SAM.work();
	for(int i = 0; i < len; ++ i)
	{
		int resA = A.query(i), resB = B.query(i);
		printf("%d\n", std::min(resA, resB - i + 1));
	}
}
posted @ 2017-07-06 11:46  Zeonfai  阅读(391)  评论(0编辑  收藏  举报