版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/My_stage/article/details/78040905
http://acm.hdu.edu.cn/showproblem.php?pid=4641
思路:
原串跑一次SAM,统计每个状态出现的次数,注意,构建的时候我们要把次数传递一下,比如我们要拆节点的时候,cnt[nq]=cnt[q] 之后我们每次添加的时候我们把答案更新,从last节点开始,每次向其父节点传递,这样我们就会得到状态出现的次数了,之后如果出现了某个状态大于k了,直接结束,说明这个状态我们已经找到过了或者说以这个状态出现的子节点一定>k次。之后每次我们得到的结果就是当前状态的最长子串-父节点的最长子串
#include <bits/stdc++.h>
#define maxs 2520202
#define mme(i,j) memset(i,j,sizeof(i))
#define ll long long int
using namespace std;
static const int MAXN = 600001<<1;
static const int LetterSize = 26;
ll ans;
int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
int cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组
int n,m ,k;
bool vis[maxs];
void init(void)
{
last = tot = 1;
len[1] = 0;
mme(cnt,0);
mme(len,0);
fa[1]=0;
memset(ch[1], 0, sizeof ch[1]);
}
void add(int x)
{
int p = last, np = ++tot;
len[np] = len[p] + 1, cnt[np] = 0;
memset(ch[np], 0, sizeof ch[np]);
while(p && !ch[p][x]) ch[p][x] = np, p = fa[p];
if(p == 0)
fa[np] = 1;
else
{
int q = ch[p][x];
if(len[q] == len[p] + 1)
fa[np] = q;
else
{
int nq = ++tot;
memcpy(ch[nq], ch[q], sizeof ch[q]);
cnt[nq]=cnt[q];
len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
while(p && ch[p][x] == q) ch[p][x] = nq, p = fa[p];
}
}
last = np;
int tmp=last;
for(; tmp!=0; tmp=fa[tmp])
{
if(cnt[tmp]>=k) break;
cnt[tmp]++;
if(cnt[tmp]>=k)
{
ans+=len[tmp]-len[fa[tmp]];
}
}
}
char s[maxs];
int main()
{
ans=0;
while(~scanf("%d%d%d",&n,&m,&k))
{
init();
scanf("%s",s);
ans=0;
int le=0;
for(; s[le]; le++)
{
add(s[le]-'a');
}
char t[3];
int op;
while(m--)
{
scanf("%d",&op);
if(op==2)
printf("%lld\n",ans);
else
{
scanf("%s",t);
add(t[0]-'a');
}
}
}
return 0;
}