后缀自动机(hdu4641多校联合)

F.A.Q
Hand In Hand
Online Acmers
Forum | Discuss
Statistical Charts
Problem Archive
Realtime Judge Status
Authors Ranklist
 
      C/C++/Java Exams     
ACM Steps
Go to Job
Contest LiveCast
ICPC@China
Best Coder beta
VIP | STD Contests
Virtual Contests 
    DIY | Web-DIY beta
Recent Contests
Author ID 
Password 
  Register new ID

K-string

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 102400/131072 K (Java/Others)
Total Submission(s): 660    Accepted Submission(s): 212


Problem Description
Given a string S. K-string is the sub-string of S and it appear in the S at least K times.It means there are at least K different pairs (i,j) so that S i,S i+1... S j  equal to this K-string. Given m operator or query:1.add a letter to the end of S; 2.query how many different K-string currently.For each query ,count the number of different K-string currently.
 

Input
The input consists of multiple test cases.  
Each test case begins with a line containing three integers n, m and K(1<=n,K<=50000,1<=m<=200000), denoting the length of string S, the number of operator or question and the least number of occurrences of K-string in the S.
The second line consists string S,which only contains lowercase letters.  
The next m lines describe the operator or query.The description of the operator looks as two space-separated integers t c (t = 1; c is lowercase letter).The description of the query looks as one integer t (t = 2).
 

Output
For each query print an integer — the number of different K-string currently.
 

Sample Input
      
      
3 5 2 abc 2 1 a 2 1 a 2
 

Sample Output
      
      
0 1 1

题意:两种操作,1是添加字符,2是查询出现K次的不同的子串有多少个

思路:在线添加查询SAM,每次添加的时候顺便维护每个节点出现多少次,询问的时候直接输出就可以了,维护的原理就是根据后缀自动机的性质,父节点跟子节点有相同的后缀,但长度短,所以每次从最后一个节点沿Parent走一遍,经过的点肯定都要加上,然后容斥一下算出每次新加的有多少个

另外用指针真的很慢啊

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=300010;
const int SIGMA_SIZE=26;
int N,M,K;
LL ans;
char s[maxn];
struct SAM_Node
{
    SAM_Node *par,*next[SIGMA_SIZE];
    int len,id,pos,cnt;
    SAM_Node(){}
    SAM_Node(int _len)
    {
        par=0;
        len=_len;
        cnt=0;
        memset(next,0,sizeof(next));
    }
};
SAM_Node node[maxn*2],*root,*last;
int SAM_size;
SAM_Node *newSAM_Node(int len)
{
    node[SAM_size]=SAM_Node(len);
    node[SAM_size].id=SAM_size;
    return &node[SAM_size++];
}
SAM_Node *newSAM_Node(SAM_Node *p)
{
    node[SAM_size]=*p;
    node[SAM_size].id=SAM_size;
    return &node[SAM_size++];
}
void SAM_add(int x)
{
    SAM_Node *p=last,*np=newSAM_Node(p->len+1);
    last=np;
    while(p&&!p->next[x])
    {
        p->next[x]=np;
        p=p->par;
    }
    if(!p)
        np->par=root;
    else
    {
        SAM_Node *q=p->next[x];
        if(q->len==p->len+1)
            np->par=q;
        else
        {
            SAM_Node *nq=newSAM_Node(q);
            nq->len=p->len+1;
            q->par=nq;
            np->par=nq;
            while(p&&p->next[x]==q)
            {
                p->next[x]=nq;
                p=p->par;
            }
        }
    }
    SAM_Node *tmp;
    for(tmp=last;tmp;tmp=tmp->par)
    {
        if(tmp->cnt==K)break;
        tmp->cnt++;
        if(tmp->cnt==K)
        {
            int num;
            if(!tmp->par)num=0;
            else num=tmp->par->len;
            ans=ans+(tmp->len)-num;
            break;
        }
    }
}
void SAM_init()
{
    SAM_size=0;
    root=last=newSAM_Node(0);
    node[0].pos=0;
}
void SAM_build(char *s)
{
    SAM_init();
    int len=strlen(s);
    for(int i=0;i<len;i++)
        SAM_add(s[i]-'a');
}
int main()
{
    int op;
    char t[5];
    while(scanf("%d%d%D",&N,&M,&K)!=EOF)
    {
        scanf("%s",s);
        ans=0;
        SAM_build(s);

        while(M--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%s",t);
                SAM_add(t[0]-'a');
            }
            else printf("%I64d\n",ans);
        }
    }
    return 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值