[SAM] hihoCoder1445 后缀自动机二·重复旋律5

来源:互联网 发布:线正数据采集处理系统 编辑:程序博客网 时间:2024/05/22 09:39

题意

给出一个只含小写字母的串 s ,求 s 的不同的子串总数。
|s|1000000

题解

SAM 最水的模板题。
直接建出 SAM ,把所有状态的 max(A)min(A)+1 全部加起来即是答案。应该不需要解释。
实现的话可以在 Extend 过程中维护,这样写比较有价值,最后扫一趟太丑啦…

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=1000005;struct node{    node *par,*ch[26]; int _max;    node(int t1=0){ _max=t1; par=0; memset(ch,0,sizeof(ch)); }    int cnt(){ return _max-par->_max; }} *root, *last;typedef node* P_node;long long ans;void Extend(char x){    P_node p=last, np=new node(p->_max+1);    while(p&&p->ch[x]==0) p->ch[x]=np, p=p->par;    if(!p) np->par=root; else{        P_node q=p->ch[x];         if(q->_max==p->_max+1) np->par=q; else{            P_node nq=new node(p->_max+1);            memcpy(nq->ch,q->ch,sizeof(q->ch));            ans-=q->cnt(); //*            nq->par=q->par; q->par=nq; np->par=nq;            ans+=q->cnt()+nq->cnt(); //*            while(p&&p->ch[x]==q) p->ch[x]=nq, p=p->par;        }    }    ans+=np->cnt(); //*    last=np;}char s[maxn];int n;int main(){    freopen("hiho1445.in","r",stdin);    freopen("hiho1445.out","w",stdout);    scanf("%s",s+1); n=strlen(s+1);    root=last=new node(0);    for(int i=1;i<=n;i++) Extend(s[i]-'a');    printf("%lld\n",ans);    return 0;}