• 后缀数据结构


    后缀自动机

    参考

    http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html

    http://blog.csdn.net/cyendra/article/details/37993603?utm_source=tuicool

     

    "一个构造好的 SAM 实际上包含了两个图:由 go 数组组成的 DAG 图;由 par 指针构成的 parent 树."

     

    设 $x$ 为自动机上一个节点(状态). 设 $s(x)$ 为 $x$ 所代表的所有子串的集合.

     

    构造信息:

    $f(x)$ : 一个满足$s(f(x)) subset s(x)$ 的 $len$ 最大的节点.

        同时也是逆序后缀树的父节点指针.

    $len(x)$ : $max(|s(x)|)$. 即节点 $x$ 所匹配的最长子串长度.

     

    扩展信息:

    $m(x)$ : $min(|s(x)|)$. 即 $x$ 所匹配的最短子串长度.

    $l(x)$ : $l(x)=len(x)-m(x)+1$ ,表示状态x所匹配的子串个数. 每个长度的子串都统计了恰好一次.

    $c(x)$ : 状态x所匹配的子串在原字符串中的出现次数. 每个 $x$ 所代表的子串均出现了这么多次.

     

    扩展信息的求法:

    用 $end$ 表示自动机的结束节点(唯一一个接受态).用 $st$ 表示自动机起点.

    $m(x)$ : 按照 $m(x)$ 的性质, $m(x)=len(f(x))+1$ .

    $l(x)$ : 算出 $m(x)$ 之后按照 $l(x)=len(x)-m(x)+1$ 扫一遍.

    $c(x)$ : 逆拓扑序DP/记忆化搜索. $c(x)=sum{c(s)}; , ; c(end)=1$ ,其中 $s$ 是$x$ 的后继结点.

         设 $s=xv$ , $v$ 是一个字符, $c(s)=c(xv)$ .$x$ 的出现次数就是 $xv$ 出现次数的和.

     

     

    AC VIJOS 1567 字串计数. 非常裸的后缀数据结构....

    DP用DFS莫名爆栈,一怒之下直接上stl的queue拓扑序DP.......

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-80;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 struct SAM
     58 {
     59     struct node
     60     {
     61         node*f;
     62         node*s[26];
     63         int v;
     64         ll cnt; 
     65         int intake;
     66         node(const node*f)
     67         { memcpy(this,f,sizeof(node)); }
     68         node(int _v)
     69         { f=NULL; memset(s,0,sizeof(s)); v=_v; cnt=-1; intake=-1; }
     70     };
     71     
     72     node*root,*cur;
     73     
     74     SAM(){root=cur=new node(0);}
     75     
     76     void expend(int v) //add a value v to the tail of current string.
     77     {
     78         node*p=cur; //the last acceptance node.
     79         cur=new node(p->v+1); //this is the new node.
     80         
     81         while(p && !p->s[v])
     82             p->s[v]=cur, p=p->f; //change transfers of portion of nodes.
     83         
     84         //stopping at this point makes no mistake.
     85         
     86         if(!p) cur->f=root; //all nodes' transfers changed.
     87         else
     88         {
     89             node*q=p->s[v]; //node that causes conflict.
     90             if(p->v+1==q->v) cur->f=q; //edit straight.
     91             else
     92             {
     93                 node*h=new node(q); //new node for conflict resolution.
     94                 h->v=p->v+1; //edit straight.
     95                 cur->f=q->f=h;
     96                 while(p && p->s[v]==q) //as our new node replaced the node q,
     97                     p->s[v]=h, p=p->f; //transfers should be changed.
     98             }
     99         }
    100     }
    101 
    102     ll DFS(node*x)
    103     {
    104         if(x->cnt!=-1) return x->cnt;
    105         ll res=0;
    106         for(int i=0;i<26;i++)
    107         if(x->s[i] && x->s[i]!=root) res+=DFS(x->s[i]);
    108         return x->cnt=res+(x!=root);
    109     }
    110     
    111     void BFS()
    112     {
    113         queue<node*> q;
    114         stack<node*> r;
    115         
    116         q.push(root);
    117         root->intake=0;
    118         while(!q.empty()) //get degrees.
    119         {
    120             node*x=q.front(); q.pop();
    121             for(int i=0;i<26;i++)
    122             if(x->s[i])
    123             {
    124                 node*y=x->s[i];
    125                 if(y->intake==-1)
    126                 {
    127                     y->intake=0;
    128                     q.push(y);
    129                 }
    130                 y->intake++;
    131             }
    132         }
    133         
    134         q.push(root);
    135         while(!q.empty()) //topo sort
    136         {
    137             node*x=q.front(); q.pop();
    138             r.push(x);
    139             for(int i=0;i<26;i++)
    140             if(x->s[i])
    141             {
    142                 node*y=x->s[i];
    143                 y->intake--;
    144                 if(y->intake==0)
    145                 q.push(y);
    146             }
    147         }
    148         
    149         while(!r.empty()) //dp
    150         {
    151             node*x=r.top(); r.pop();
    152             x->cnt=1;
    153             for(int i=0;i<26;i++)
    154             if(x->s[i]) x->cnt+=x->s[i]->cnt;
    155         }
    156     }
    157     
    158 };
    159 
    160 
    161 int n;
    162 
    163 char a[205000];
    164 
    165 int main()
    166 {
    167     SAM T;
    168     n=getint();
    169     for(int i=0;i<n;i++)
    170     {
    171         char c=getchar();
    172         while(c<'a' || 'z'<c) c=getchar();
    173         a[i]=c;
    174         T.expend(c-'a');
    175     }
    176     
    177     T.BFS();
    178     
    179     printf("%I64d
    ",T.root->cnt-1);
    180     
    181     
    182     return 0;
    183 }
    View Code

    DAGDP,用 $cnt(x)$ 表示,从节点x出发,能走出的路径的条数.

    那么直接在DAG上做DP, $cnt(x)=1+cnt(s)$ . $s$ 是 $x$ 的后继状态.

    最后的答案要减去从root走到root(空串)的一个方案.

    另外,如果是能走到终止状态的路径条数,那么显然是字符串的长度 $n$ ,因为每一条走到终止状态的路径都代表了原串的唯一一个后缀.

     

     

    AC SPOJ 1811 (LCS) 最长公共子串

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-80;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 int s[500050][26];
     58 int f[500050];
     59 int len[500050];
     60 int dep[500050];
     61 int nt;
     62 int root;
     63 int cur;
     64 
     65 int newnode(int l)
     66 { memset(s[nt],0,sizeof(s[nt]));f[nt]=0;len[nt]=l;return nt++; }
     67 
     68 void Expend(int v)
     69 {
     70     int p=cur;
     71     cur=newnode(len[p]+1); 
     72     
     73     while(p && !s[p][v])
     74     s[p][v]=cur,p=f[p];
     75     
     76     if(!p) f[cur]=root;
     77     else
     78     {
     79         int q=s[p][v];
     80         if(len[p]+1==len[q]) f[cur]=q;
     81         else
     82         {
     83             int h=newnode(len[p]+1);
     84             memcpy(s[h],s[q],sizeof(s[h]));
     85             f[h]=f[q];
     86             
     87             f[cur]=f[q]=h;
     88             while(p && s[p][v]==q)
     89             s[p][v]=h,p=f[p];
     90         }
     91     }
     92 }
     93 
     94 int n;
     95 
     96 char a[250050];
     97 char b[250050];
     98 
     99 
    100 int main()
    101 {
    102     nt=1;
    103     root=cur=newnode(0);
    104     
    105     scanf("%s%s",a,b);
    106     n=strlen(a);
    107     for(int i=0;i<n;i++)
    108     Expend(a[i]-'a');
    109     
    110     n=strlen(b);
    111     int res=0;
    112     int ans=0;
    113     int x=root;
    114     for(int i=0;i<n;i++)
    115     {
    116         int v=b[i]-'a';
    117         
    118         if(s[x][v]) res++,x=s[x][v];
    119         else
    120         {
    121             while(x && !s[x][v]) x=f[x];
    122             if(x) res=len[x]+1,x=s[x][v];
    123             else res=0,x=root;
    124         }
    125         
    126         ans=max(ans,res);
    127     }
    128     
    129     printf("%d
    ",ans);
    130     
    131     return 0;
    132 }
    View Code

    注意len的意义. 如果匹配,直接把统计值加1.

    如果失配,那么就要依次考察f(x),f(f(x))....

    注意,当我们匹配到状态 $x$ 的时候,实际上我们已经匹配了一大堆字符串的后缀.

    设当前需要匹配的字符为 $x$ ,如果 $x$ 的 $c$ 转移不存在,说明失配了.

    那么我们通过 $f$ 转移,就意味着不断缩短当前匹配串的长度,这个时候会有新的已匹配串加入进来,它们可能可以匹配 $x$ .

    如果找不到这样的状态说明当前没法转移了,直接把数据初始化.

     

    AC SPOJ 8222 Substrings

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-80;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 int s[500050][26];
     58 int f[500050];
     59 int len[500050];
     60 int dep[500050];
     61 int c[505000];
     62 int nt;
     63 int root;
     64 int cur;
     65 
     66 int newnode(int l)
     67 { memset(s[nt],0,sizeof(s[nt]));f[nt]=0;len[nt]=l;return nt++; }
     68 
     69 void Expend(int v)
     70 {
     71     int p=cur;
     72     cur=newnode(len[p]+1); 
     73     
     74     while(p && !s[p][v])
     75     s[p][v]=cur,p=f[p];
     76     
     77     if(!p) f[cur]=root;
     78     else
     79     {
     80         int q=s[p][v];
     81         if(len[p]+1==len[q]) f[cur]=q;
     82         else
     83         {
     84             int h=newnode(len[p]+1);
     85             memcpy(s[h],s[q],sizeof(s[h]));
     86             f[h]=f[q];
     87             
     88             f[cur]=f[q]=h;
     89             while(p && s[p][v]==q)
     90             s[p][v]=h,p=f[p];
     91         }
     92     }
     93 }
     94 
     95 int n;
     96 int v[500050];
     97 int p[500050];
     98 int r[500050];
     99 char a[250050];
    100 
    101 
    102 int main()
    103 {
    104     nt=1;
    105     root=cur=newnode(0);
    106     
    107     scanf("%s",a);
    108     n=strlen(a);
    109     for(int i=0;i<n;i++)
    110     Expend(a[i]-'a');
    111     
    112     int x=root;
    113     int i=0;
    114     do {  x=s[x][a[i++]-'a']; if(x)c[x]=1; } while(x);
    115     
    116     for(int i=1;i<nt;i++) v[len[i]]++;
    117     for(int i=1;i<=n;i++) v[i]+=v[i-1];
    118     for(int i=1;i<nt;i++) p[v[len[i]]--]=i;
    119     for(int i=nt-1;i>=1;i--) 
    120     r[len[p[i]]]=max(r[len[p[i]]],c[p[i]]),c[f[p[i]]]+=c[p[i]];
    121     for(int i=1;i<=n;i++) printf("%d
    ",r[i]);
    122     
    123     return 0;
    124 }
    View Code

    对DP方程的理解参照 http://blog.csdn.net/huyuncong/article/details/7583214

    用逆序后缀树的话叶子数就是出现次数.

    基数排序实际上就是保证了先更新子节点再更新父节点.因为叶子节点的 $len$ 总是会比父亲大.

     

     

     

     

    后缀数组

     AC BZOJ 1031

     1 int n,m;
     2 int s[405000];
     3 int p[405000];
     4 int r[405000];
     5 int h[405000];
     6 
     7 int step;
     8 bool cmpr(const int&a,const int&b)
     9 { return r[a]==r[b] ? r[a+step]<r[b+step] : r[a]<r[b]; }
    10 bool cmps(const int&a,const int&b)
    11 { return s[a]<s[b]; }
    12 
    13 void GetRank(int*f,int*x,int*v)
    14 //f:resault array; x:pointer array; v:value array.
    15 {
    16     int t=1;
    17     f[x[0]]=t;
    18     for(int i=1;i<n;i++)
    19     {
    20         if(v[x[i]]!=v[x[i-1]] || v[x[i]+step]!=v[x[i-1]+step]) t++;
    21         f[x[i]]=t;
    22     }
    23 }
    24 
    25 void Build()
    26 {
    27     for(int i=0;i<n;i++) p[i]=i;
    28     step=0;
    29     sort(p,p+n,cmps);
    30     GetRank(r,p,s);
    31     for(step=1;step<=n;step<<=1)
    32     {
    33         sort(p,p+n,cmpr);
    34         memcpy(h,r,sizeof(int)*n);
    35         GetRank(r,p,h);
    36     }
    37 }
    38 
    39 char inp[105000];
    40 int res[105000];
    41 
    42 int main()
    43 {
    44     int ip=0;
    45     char c=getchar();
    46     while(c!='
    ' && !feof(stdin)) inp[ip++]=c,c=getchar();
    47     
    48     n=strlen(inp);
    49     for(int i=0;i<n;i++)
    50     s[i]=inp[i];
    51     memcpy(s+n,s,sizeof(int)*n);
    52     n<<=1;
    53     
    54     Build();
    55     
    56     n>>=1;
    57     
    58     int rt=0;
    59     for(int i=0;i<(n<<1);i++)
    60     if(p[i]<n) res[rt++]=s[p[i]+n-1];
    61     
    62     for(int i=0;i<n;i++) printf("%c",(char)res[i]);
    63     printf("
    ");
    64     
    65     return 0;
    66 }
    View Code

    O(nlog2n)的算法. 倍增+快速排序.

    本地跑极限数据2s.....交上去1.8s水过......

    思路在程序里写得很清楚了...

    先求出长度 2n-1 的所有字串的rank....

    再使用rank作为关键字(双关键字,两个关键字都在rank数组中)排序,

    然后用排序了的指针再求出 2n 的所有字串的rank.....

    这样倍增地排序直到长度 2n >len .....

    就行啦....

     

     妈呀计数排序居然可以这么玩!!

     1 int n,m;
     2 
     3 int _v[5005000];
     4 int _r[5005000];
     5 int _p[5005000];
     6 void CountingSort(int*p,int*fv,int*sv,int len)
     7 {
     8     //second key sort.
     9     memset(_v,0,sizeof(int)*(m+1));
    10     for(int i=0;i<len;i++) _v[sv[i]]++;
    11     for(int i=1;i<m;i++) _v[i]+=_v[i-1];
    12     for(int i=len-1;i>=0;i--) _p[--_v[sv[i]]]=i;
    13     //first key sort.
    14     memset(_v,0,sizeof(int)*(m+1));
    15     for(int i=0;i<len;i++) _v[fv[_p[i]]]++;
    16     for(int i=1;i<m;i++) _v[i]+=_v[i-1];
    17     for(int i=len-1;i>=0;i--) p[--_v[fv[_p[i]]]]=_p[i];
    18 }
    View Code

    计数排序如何排双关键字呢?

    先把第二关键字排序,拿到排序指针(p[i]表示第i小的元素的下标)

    然后.....按照p[i]的顺序(即,以p[i]作下标代替原来的0,1..,n-1)再来一次计数排序....

     

    下面是标准写法的SA. AC BZOJ 1031

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-80;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 int n,m=257;
     58 int s[405000];
     59 int p[405000];
     60 int _p[405000];
     61 int r[2][405000];
     62 int v[405000];
     63 
     64 int step;
     65 
     66 void GetRank(int*f,int*x,int*v)
     67 //f:resault array; x:pointer array; v:value array.
     68 {
     69     int t=0;
     70     f[x[0]]=t;
     71     for(int i=1;i<n;i++)
     72     {
     73         if(v[x[i]]!=v[x[i-1]] || v[x[i]+step]!=v[x[i-1]+step]) t++;
     74         f[x[i]]=t;
     75     }
     76 }
     77 
     78 void Build()
     79 {
     80     step=0;
     81     int k=0;
     82     for(int i=0;i<n;i++) v[s[i]]++;
     83     for(int i=1;i<m;i++) v[i]+=v[i-1];
     84     for(int i=0;i<n;i++) p[--v[s[i]]]=i;
     85     GetRank(r[!k],p,s); k=!k;
     86     for(step=1;step<=n;step<<=1)
     87     {
     88         //second key sort. using pointer array p.
     89         int c=0;
     90         for(int i=n-step;i<n;i++) _p[c++]=i;
     91         for(int i=0;i<n;i++) if(p[i]>=step) _p[c++]=p[i]-step; 
     92         
     93         //first key sort.
     94         memset(v,0,sizeof(int)*(n+1));
     95         for(int i=0;i<n;i++) v[r[k][i]]++;
     96         for(int i=1;i<m;i++) v[i]+=v[i-1];
     97         for(int i=n-1;i>=0;i--) p[--v[r[k][_p[i]]]]=_p[i];
     98           
     99         GetRank(r[!k],p,r[k]); k=!k; 
    100     }
    101 }
    102 
    103 char inp[105000];
    104 int res[105000];
    105 
    106 int main()
    107 {
    108     int ip=0;
    109     char c=getchar();
    110     while(c!='
    ' && !feof(stdin)) inp[ip++]=c,c=getchar();
    111     
    112     n=strlen(inp);
    113     for(int i=0;i<n;i++)
    114     s[i]=inp[i];
    115     memcpy(s+n,s,sizeof(int)*(n+1));
    116     
    117     n<<=1;
    118     m=max(m,n+2); //for characters and ranks' public value range.
    119     
    120     Build();
    121     
    122     n>>=1;
    123     
    124     int rt=0;
    125     for(int i=0;i<(n<<1);i++)
    126     if(p[i]<n) res[rt++]=s[p[i]+n-1];
    127     
    128     for(int i=0;i<n;i++) printf("%c",(char)res[i]);
    129     printf("
    ");
    130     
    131     return 0;
    132 }
    View Code

    再次突显常数优化重要性......用时840ms....还是打不过各路神犇TAT

     

    再来一题,跟上边的差不多,但是多解的情况要让靠前的作为输出.

    于是乎,把第二关键字排序换回原来的形式......

    就可以稳定排序了0.0 下面是代码

    AC VISOS 1437

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-80;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 int n,m=257;
     58 int s[405000];
     59 int p[405000];
     60 
     61 int step;
     62 
     63 int GetRank(int*f,int*x,int*v)
     64 {
     65     int t=0;
     66     f[x[0]]=t;
     67     for(int i=1;i<n;i++)
     68     {
     69         if(v[x[i]]!=v[x[i-1]] || v[x[i]+step]!=v[x[i-1]+step]) t++;
     70         f[x[i]]=t;
     71     }
     72     return t+1;
     73 }
     74 
     75 int r[2][405000];
     76 int _p[405000];
     77 int v[405000];
     78 void Build(int*p,int*x,int*y)
     79 {
     80     step=0;
     81     for(int i=0;i<n;i++) v[s[i]]++;
     82     for(int i=1;i<m;i++) v[i]+=v[i-1];
     83     for(int i=n-1;i>=0;i--) p[--v[s[i]]]=i;
     84     m=max(m,GetRank(x,p,s));
     85     for(step=1;step<=n;step<<=1)
     86     {
     87         //second key sort.
     88         memset(v,0,sizeof(int)*(n+1));
     89         for(int i=0;i<n;i++) v[x[i+step]]++;
     90         for(int i=1;i<m;i++) v[i]+=v[i-1];
     91         for(int i=n-1;i>=0;i--) _p[--v[x[i+step]]]=i;
     92         
     93         //first key sort.
     94         memset(v,0,sizeof(int)*(n+1));
     95         for(int i=0;i<n;i++) v[x[i]]++;
     96         for(int i=1;i<m;i++) v[i]+=v[i-1];
     97         for(int i=n-1;i>=0;i--) p[--v[x[_p[i]]]]=_p[i];
     98           
     99         m=max(m,GetRank(y,p,x)); swap(x,y);
    100     }
    101 }
    102 
    103 char inp[205000];
    104 
    105 int main()
    106 {
    107     n=getint();
    108     for(int i=0;i<n;i++)
    109     { char c=getchar(); while(c<'a' || 'z'<c) c=getchar(); inp[i]=c;  }
    110     memcpy(inp+n,inp,sizeof(char)*n);
    111     n<<=1;
    112     
    113     for(int i=0;i<n;i++) s[i]=inp[i]-'a';
    114     m=27;
    115     
    116     Build(p,r[0],r[1]);
    117     
    118     //for(int i=0;i<n;i++)
    119     //if(p[i]<n/2) { printf("%d %d:",i,p[i]); for(int j=p[i];j<p[i]+n/2;j++) printf("%c",inp[j]); printf(" "); for(int j=p[i]+n/2;j<n;j++) printf("%c",inp[j]); printf("
    "); }
    120     
    121     for(int i=0;i<n;i++)
    122     if(p[i]<n/2)
    123     {
    124         printf("%d
    ",p[i]);
    125         break;
    126     }
    127     
    128     return 0;
    129 }
    View Code

     

     

     

    未完待续

     

     

    后缀树

     

  • 相关阅读:
    java 异常处理
    c/c++ 多维数组和指针
    c/c++ 数组和指针
    c/c++ 数组 数组的引用,指针数组的引用
    c/c++ 标准库 迭代器(iterator)
    c/c++ 标准库 vector
    c/c++ 标准库 string
    c/c++ 模板与STL小例子系列<三> traits
    c++ 右值引用,move关键字
    c/c++ 右值引用
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4338989.html
Copyright © 2020-2023  润新知