zoukankan      html  css  js  c++  java
  • BZOJ4516 [Sdoi2016]生成魔咒

    题意:

    一个初始为空的串,每次在末尾插入一个字符,每次插入后问字符串中本质不同的子串的个数。字符值域1e9。

    知识点:

    后缀自动机

    解法:

    因为SAM本来就是支持动态末尾插入的在线结构,而且SAM有一个性质是本质不同子串个数等于所有点的len减去parent树上的父亲点的len,所以每次插入改ans即可。

    备注:

    因为值域很大,所以改用map维护转移的字符。
    另外好像后缀数组也可以做,加点什么平衡树也可以做,不过我这种方法应该代码最好写、最短(里面有一些map的find、insert操作可以在访问空节点的时候变快)。

    #include<cstdio>
    #include<cstring>
    #include<map>
    using namespace std;
    
    typedef long long ll;
    const int maxn=200010;
    ll ans;
    int n,m,tot,lst;
    struct sam
    {
    	map<int,int>son;
    	int fa,len;
    }a[maxn];
    
    int read()
    {
    	int x=0;
    	char c=getchar();
    	while (c<48||c>57)
    		c=getchar();
    	while (c>=48&&c<=57)
    		x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    
    void sam_insert(int c)
    {
    	int p=lst,u=(++tot);
    	lst=u;
    	a[u].len=a[p].len+1;
    	for (;p&&a[p].son.find(c)==a[p].son.end();p=a[p].fa)
    		a[p].son.insert(make_pair(c,u));
    	if (!p)
    		a[u].fa=1;
    	else
    	{
    		int v=a[p].son[c];
    		if (a[v].len==a[p].len+1)
    			a[u].fa=v;
    		else
    		{
    			int w=(++tot);
    			a[w]=a[v];
    			a[w].len=a[p].len+1;
    			a[v].fa=a[u].fa=w;
    			for (;p&&a[p].son[c]==v;p=a[p].fa)
    				a[p].son[c]=w;
    		}
    	}
    	ans+=a[u].len-a[a[u].fa].len;
    }
    
    int main()
    {
    	int x;
    	tot=lst=1;
    	n=read();
    	while (n--)
    	{
    		x=read();
    		sam_insert(x);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [luogu] P1440 求m区间内的最小值
    [NOI2014]起床困难综合症
    [SDOI2009]地图复原
    [USACO08JAN] Cow Contest
    【洛谷P5049】旅行(数据加强版)
    【NOIP2015】真题回顾
    【NOIP2014】真题回顾
    【UVA11987】Almost Union-Find
    【UVA11988】破损的键盘
    【UVA11134】传说中的车
  • 原文地址:https://www.cnblogs.com/Ronald-MOK1426/p/12294374.html
Copyright © 2011-2022 走看看