做得心 力 憔 悴

Description

你有一个字符串S,一开始为空串,要求支持两种操作
在S后面加入字母C
删除S最后一个字母
问每次操作后S有多少个两两不同的连续子串

Input

一行一个字符串Q,表示对S的操作
如果第i个字母是小写字母c,表示第一种加字母c的操作
如果为-表示删除操作,保证所有删除操作前S都非空
|Q|<=10^5

Output

输出|Q|行,第i行表示i个操作之后S内有多少个不同子串

题目分析

陈老师神题x2,暂时只会做法一。

做法一:暴力回退

还是自己菜啊……这么个暴力都写了老久。

思路就是将每一次的修改值都记录下来,再在$undo()$里回退每一个修改。说得是轻松,但是具体的实现还是要仔细安排一下顺序和细节的。

其中$stk[top]$存修改的起止点;$last[]$存每次$extend()$前的$lst$值,用于路径回退上的$ch[x][c]$修改;$tag[]$表示点$i$这次操作新增点的数量,需要分为1,2讨论回退;$val[]$表示每次操作插入的字符$c$.

有2个新增点的$undo()$稍微复杂一点,这里$stk[]={从lst回退的p';fa[q];再次回退的p'';q}$.

 #include<bits/stdc++.h>
const int maxn = ; int n,top,stk[maxn<<],last[maxn<<],tag[maxn<<],val[maxn<<];
long long ans;
struct SAM
{
int ch[maxn][],fa[maxn],len[maxn],lst,tot;
void init()
{
lst = tot = ;
}
void extend(int c)
{
int p = lst, np = ++tot;
last[++last[]] = lst;
lst = np, len[np] = len[p]+;
val[tot] = c;
for (; p&&!ch[p][c]; p=fa[p]) ch[p][c] = np;
tag[tot] = , stk[++top] = p;
if (!p) fa[np] = ;
else{
int q = ch[p][c];
if (len[p]+==len[q]) fa[np] = q;
else{
int nq = ++tot;
len[nq] = len[p]+;
tag[tot] = , val[tot] = c;
memcpy(ch[nq], ch[q], sizeof ch[q]);
stk[++top] = fa[q];
fa[nq] = fa[q], fa[q] = fa[np] = nq;
for (; p&&ch[p][c]==q; p=fa[p]) ch[p][c] = nq;
stk[++top] = p, stk[++top] = q;
}
}
ans += len[np]-len[fa[np]];
if (!tag[tot]) tag[tot] = ;
}
void undo()
{
if (tag[tot]==){
int p = last[last[]--], fnd = stk[top--], c = val[tot];
ans -= len[tot]-len[fa[tot]], lst = p;
for (; p!=fnd; p=fa[p]) ch[p][c] = ;
memset(ch[tot], , sizeof ch[tot]), --tot;
}else{
int q = stk[top--], fnd2 = stk[top--], fatq = stk[top--], fnd1 = stk[top--];
int p = last[last[]--], c = val[tot];
ans -= len[tot-]-len[fa[tot-]], lst = p;
for (; p!=fnd1; p=fa[p]) ch[p][c] = ;
fa[q] = fatq;
for (; p!=fnd2; p=fa[p]) ch[p][c] = q;
memset(ch[tot], , sizeof ch[tot]), --tot;
memset(ch[tot], , sizeof ch[tot]), --tot;
}
}
}f;
char s[maxn]; int main()
{
f.init();
scanf("%s",s+);
n = strlen(s+);
for (int i=; i<=n; i++)
{
if (s[i]=='-') f.undo();
else f.extend(s[i]-'a');
printf("%lld\n",ans);
}
return ;
}

做法二:后缀平衡树

具体的实现似乎可以用hash求LCP+multiset解决

END

【SAM】bzoj5084: hashit的更多相关文章

  1. 【SAM】codevs3160-最长公共子串

    [题目大意] 求两个字符串的最长公共子串. [思路] 对第一个字符串建立后缀自动机,第二个字符串去匹配.cnt记录当前最长公共子串的长度,而ret记录答案. p代表位置指针,初始在rt位置. 对于第二 ...

  2. 【SAM】BZOJ2882-工艺

    [题目大意] 求一个循环数列的最小表示法. [思路] 最小表示法的正解:★ SAM乱搞,和前面的POJ那道一样.然而MLE了,当作学习一下map的用法^ ^ map的使用方法(来源:☆) 一.map的 ...

  3. 【SAM】BZOJ3998-弦论

    [题目大意] 给出一个字符串,求第k大的子串.(输入1表示子串可重复,0表示不可重复) [思路] 显然,k大子串是后缀自动机的经典题型,可以利用后缀自动机的性质来解决.对于字符串 [前铺1]" ...

  4. 【SAM】POJ1509-Glass Beads

    [题目大意] 求一个循环数列的最小表示法. [思路] 把原创复制一遍放在后面,建立SAM,从s按字典序开始跑长度L即可. 板子来源(作者见连接内):

  5. 【SPOJ - LCS2】Longest Common Substring II【SAM】

    题意 求出多个串的最长公共子串. 分析 刚学SAM想做这个题的话最好先去做一下那道codevs3160.求两个串的LCS应该怎么求?把一个串s1建自动机,然后跑另一个串s2,然后找出s2每个前缀的最长 ...

  6. 【SAM】loj#6401. 字符串

    网上有篇题解写的是线段树合并维护求值? 题目描述 有一个只包含小写字母,长度为 $n$ 的字符串 $S$ .有一些字母是好的,剩下的是坏的. 定义一个子串 $S_{l\ldots r}$是好的,当且仅 ...

  7. bzoj 2946: [Poi2000]公共串【SAM】

    对第一个串建SAM,把剩下的串在上面跑,每次跑一个串的时候在SAM的端点上记录匹配到这的最大长度,然后对这些串跑的结果取min,然后从这些节点的min中取max就是答案 注意在一个点更新后它的祖先也会 ...

  8. bzoj 4698: Sdoi2008 Sandy的卡片【SAM】

    差分之后用SAM求LCS,然后答案就是LCS+1 #include<iostream> #include<cstdio> #include<cstring> usi ...

  9. bzoj 3926: [Zjoi2015]诸神眷顾的幻想乡【SAM】

    有一个显然的性质就是每个串一定在某个叶子为根的树中是一条直的链 然后因为SAM里是不会有相同状态的,所以以每个叶子为根dfs一遍,并且动态构造SAM(这里的节点u的last指向父亲),最后统计答案就是 ...

随机推荐

  1. Nginx在Linux里安装 以及nginx实现负载均衡

    Nginx 一.在Linux里安装软件 1. rpm命令 rpm: redhat package manager,红帽软件包管理套件 常用命令: 安装:rpm -ivh 软件包 i :安装模式 v : ...

  2. PJzhang:kali linux安装金山wps、永中office、sougoupinyin、ibuspiyin

    猫宁!!! 参考链接:https://www.cnblogs.com/liuxingbusi/p/9277127.html https://www.cnblogs.com/xcb0730/p/6808 ...

  3. Python-8-print和import进阶

    1.打印多个参数 用逗号隔开: >>> print('Age:', 42) Age: 42 参数之间自动插入了一个空格字符 >>> name = 'Gumby' & ...

  4. 牛客假日团队赛2 F.跳跃

    链接: https://ac.nowcoder.com/acm/contest/924/F 题意: Farmer John为了满足奶牛对美的享受而安装了人工湖.矩形的人工湖分成M行N列(1 <= ...

  5. GYM 101933K(二项式反演、排列组合)

    方法一 设\(f_i\)为最多使用\(i\)种颜色的涂色方案,\(g_i\)为恰好只使用\(i\)种颜色的涂色方案.可知此题答案为\(g_k\). 根据排列组合的知识不难得到\(f_k = \sum_ ...

  6. 随机算法瞎练BZOJ3237&3563&3569三倍经验题

    随机方法真的好骚啊O(∩_∩)O~ 最早的时候miaom提出一个奇怪的东西: 判断一个数列中是否有0/1/2个数出现奇数次 对每个数赋一个随机权值,异或乱搞,对于判2的情况用一个(可能类似线性基的)方 ...

  7. 不可见类有抽象父类,spring配置子类bean,注入父类,aop就可以切父类的方法

    public class TestBeanChild { int b = 1; public TestBean createDefault() { return new TestBeanDefault ...

  8. Jmeter4.0----监控服务器性能(7)

    1.说明 JMeter是一款压力测试工具. 通常在压力测试中我们也需要监控和知道服务器的相关资源情况,jmeter本身不具备这个功能,今天我们主要说一下如何通过JMeter插件来监控服务器CPU.内存 ...

  9. 常见的HTTP状态码说明

    1.说明 HTTP服务器状态代码定义(Status Code Definitions) 做测试的时候,会产生比较多的HTTP错误,查看其错误,有超时的,链接不到图片的,连接不到服务器等等,很多人经常忘 ...

  10. Announcing .NET Core 2.1

    Announcing .NET Core 2.1 https://blogs.msdn.microsoft.com/dotnet/2018/05/30/announcing-net-core-2-1/ ...