[TJOI2013]单词

来源:互联网 发布:内江百科线材优化系统 编辑:程序博客网 时间:2024/05/02 21:56

题目大意

一篇文章由n个单词组成。询问每个单词在文章中作为某单词(包括自己)的子串总共出现了多少次(如果在某单词中多次出现,算多次)?
单词都由小写字母组成。

令单词总长为LL10000001n200


题目分析

Trie上建一个SAM,然后直接计算即可。
当然如果使用SAM构造广义后缀树的话代码会简单很多,但是我目前还不会。学习了之后会进行更新。
TTrieg(T)T的最大深度,则时间复杂度O(|T||Σ|+g(T))


代码实现

#include <algorithm>#include <iostream>#include <cstring>#include <cctype>#include <cstdio>#include <cmath>using namespace std;const int N=1005000;const int S=N<<1;const int C=26;int que[S],head,tail;struct Node{    int prt,len,size,deg;    int next[C];}sam[S];int tot;int ins(int x,int c,int s){    int p=x,np=++tot;    for (sam[np].size=s,sam[np].len=sam[p].len+1;p&&!sam[p].next[c];p=sam[p].prt)        sam[p].next[c]=np;    if (!p)        sam[np].prt=1;    else    {        int q=sam[p].next[c];        if (sam[q].len==sam[p].len+1)            sam[np].prt=q;        else        {            int nq=++tot;            sam[nq]=sam[q],sam[nq].size=0;            sam[nq].len=sam[p].len+1;            sam[nq].prt=sam[q].prt;            sam[q].prt=sam[np].prt=nq;            for (;p&&sam[p].next[c]==q;p=sam[p].prt)                sam[p].next[c]=nq;        }    }    return np;}void calc(){    for (int i=2;i<=tot;i++) sam[sam[i].prt].deg++;    for (int i=2;i<=tot;i++)        if (!sam[i].deg) que[++tail]=i;    int x;    while (head!=tail)    {        x=que[++head];        sam[sam[x].prt].size+=sam[x].size;        if (!--sam[sam[x].prt].deg&&x!=1)            que[++tail]=sam[x].prt;    }}struct Trie{    int next[N][C],suf[N],size[N];    int tot;    int newnode()    {        for (int c=0;c<C;c++) next[tot][c]=0;        suf[tot]=size[tot]=0;        return tot++;    }    int insert(int rt,int c)    {        if (!next[rt][c]) next[rt][c]=newnode();        rt=next[rt][c],size[rt]++;        return rt;    }    void build(int rt)    {        for (int c=0,x;c<C;c++)            if (x=next[rt][c])                suf[x]=ins(suf[rt],c,size[x]),build(x);    }}t;char s[N];int n,l;int main(){    freopen("word.in","r",stdin);    freopen("word.out","w",stdout);    scanf("%d",&n);    l=0;    t.tot++;    for (int i=1;i<=n;i++)    {        char ch=getchar();        int rt=0;        while (!isalpha(ch)) ch=getchar();        while (isalpha(ch)) s[l]=ch,rt=t.insert(rt,s[l++]-'a'),ch=getchar();        s[l++]='$';    }    t.suf[0]=tot=1;    t.build(0);    calc();    for (int i=1,cur=0,p;i<=n;i++)    {        p=1;        while (s[cur]!='$') p=sam[p].next[s[cur++]-'a'];        cur++;        printf("%d\n",sam[p].size);    }    fclose(stdin);    fclose(stdout);}
0 0
原创粉丝点击