zoukankan      html  css  js  c++  java
  • 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
    ", std::min(resA, resB - i + 1));
    	}
    }
    
  • 相关阅读:
    getpass模块和random模块
    【转】Monkeyrunner测试1——Monkeyrunner的使用
    adb uninstall卸载apk 命令后跟的是包的名称
    【转】Android应用程序的数据存放目录解说
    【转】adb uninstall卸载apk文件说明
    【转】野兽成长史:张颖搭手傅盛在2008
    傅盛
    【转】傅盛:怎样做一个创业公司CEO?
    【转】搜狗测试经理分享
    性能测试积累
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7125516.html
Copyright © 2011-2022 走看看