后缀数据结构

后缀自动机

参考

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\n",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\n",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\n",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!='\n' && !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("\n");
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!='\n' && !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("\n");
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("\n"); }
120     
121     for(int i=0;i<n;i++)
122     if(p[i]<n/2)
123     {
124         printf("%d\n",p[i]);
125         break;
126     }
127     
128     return 0;
129 }
View Code

 

 

 

未完待续

 

 

后缀树

 

posted @ 2015-03-15 11:25  DragoonKiller  阅读(430)  评论(0编辑  收藏  举报