做得心 力 憔 悴

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. git push error: ! [rejected] failed to push some refs to . . .

    报错情况: 报错原因:远程库与本地库不一致造成的,需要把远程库同步到本地库! 解决办法: git pull --rebase origin master 这条指令是将远程库中的更新合并到本地库,--r ...

  2. excel 公式2列合并

    =A2&"="&C2 ="UPDATE comm_department SET parent_id='"&D2&"' ...

  3. [软件工程基础]Alpha 软件测试报告

    PhyLab Alpha 测试报告 测试中发现的bug Alpha版本限制与问题 由于接手时数据库已经丢失,这一版本主要修复了大部分数据库,使得网站得以运行. 相比接手时网站的状况,有以下改进: 恢复 ...

  4. C.One Piece

    链接:https://ac.nowcoder.com/acm/contest/908/C 题意: Luffy once saw a particularly delicious food, but h ...

  5. 通过jcrop和canvas的画布功能完成对图片的截图功能与视频的截图功能实现

    最近因为工作需要,做了视频截图和图截图的功能.大概需求是,用户点击某个按钮,可以对图片区域进行部分截取,然后进行进一步的业务操作. 首先说图片截图功能的思路, (1)下载Jcrop插件,添加css和j ...

  6. 064 Minimum Path Sum 最小路径和

    给定一个只含非负整数的 m x n 网格,找到一条从左上角到右下角的可以使数字之和最小的路径.注意: 每次只能向下或者向右移动一步.示例 1:[[1,3,1], [1,5,1], [4,2,1]]根据 ...

  7. Java VisualVM添加Visual GC插件

    1.访问地址:https://visualvm.github.io/pluginscenters.html,找到自己JDK版本对应的插件下载地址(我的JDK版本为1.7.0_67): 2.点击该链接进 ...

  8. Centos安装TensorFlow和Keras

    安装命令如下: curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py python get-pip.py pip install tensor ...

  9. 在MasterPage中检验session是否存在~

    在母板頁中檢查user是否登入過,這樣就不用在每個頁中去作檢驗.在其Init事件中寫入如下代碼:     protected void ContentPlaceHolder1_Init(object  ...

  10. display:none和visibility:hidden v-show和v-if的区别

    隐藏元素display:none 和 visibility:hidden的区别visibility:hidden可以隐藏某个元素,但是隐藏的元素仍要占据空间,仍要影响布局display:none不会占 ...