写的还比较详细,所以本蒟蒻就不再自己写一个了……
用SAM建广义后缀树
TJOI的单词
离线构造
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=2500000+10;
int pre[maxn],step[maxn],size[maxn],g[maxn][27],id[maxn];
char s[maxn],ch;
int i,j,k,l,t,n,m,tot,top,last;
struct dong{
int len,id;
} a[250];
bool operator <(dong a,dong b){
return a.len<b.len;
}
char get(){
char ch=getchar();
while (ch<'a'||ch>'z') ch=getchar();
return ch;
}
void insert(char ch){
if (g[last][ch-'a']&&step[g[last][ch-'a']]==step[last]+1){
last=g[last][ch-'a'];
size[last]++;
return;
}
int np=++tot;
size[np]=1;
step[np]=step[last]+1;
int p=last;
while (p&&g[p][ch-'a']==0){
g[p][ch-'a']=np;
p=pre[p];
}
if (!p) pre[np]=1;
else{
int q=g[p][ch-'a'];
if (step[q]==step[p]+1) pre[np]=q;
else{
int nq=++tot;
step[nq]=step[p]+1;
pre[nq]=pre[q];
pre[q]=nq;
int i;
fo(i,0,26) g[nq][i]=g[q][i];
pre[np]=nq;
while (p&&g[p][ch-'a']==q){
g[p][ch-'a']=nq;
p=pre[p];
}
}
}
last=np;
}
bool cmp(int a,int b){
if (step[a]<step[b]) return 1;
else if (step[a]==step[b]&&a>b) return 1;
else return 0;
}
int main(){
//freopen("word4.in","r",stdin);freopen("3127.out","w",stdout);
scanf("%d",&n);
tot=1;
fo(i,1,n){
s[++top]=get();
while (1){
ch=getchar();
if (ch<'a'||ch>'z') break;
s[++top]=ch;
}
s[++top]='a'+26;
a[i].len=top-a[i-1].id-a[i-1].len-1;
a[i].id=top-a[i].len;
}
sort(a+1,a+n+1);
fo(i,1,n){
last=1;
fo(j,a[i].id,a[i].id+a[i].len-1) insert(s[j]);
}
fo(i,1,tot) id[i]=i;
sort(id+1,id+tot+1,cmp);
fd(i,tot,1)
if (pre[id[i]]>1) size[pre[id[i]]]+=size[id[i]];
j=1;
fo(i,1,top){
if (s[i]=='a'+26){
printf("%d\n",size[j]);
j=1;
}
else j=g[j][s[i]-'a'];
}
}
在线构造
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=2500000+10;
int pre[maxn],step[maxn],size[maxn],g[maxn][27],id[maxn];
char s[maxn],ch;
int i,j,k,l,t,n,m,tot,top,last;
char get(){
char ch=getchar();
while (ch<'a'||ch>'z') ch=getchar();
return ch;
}
void insert(char ch){
if (g[last][ch-'a']){
int p=last,q=g[p][ch-'a'];
if (step[q]==step[p]+1){
last=g[last][ch-'a'];
size[last]++;
}
else{
int nq=++tot;
step[nq]=step[p]+1;
pre[nq]=pre[q];
pre[q]=nq;
int i;
fo(i,0,26) g[nq][i]=g[q][i];
while (p&&g[p][ch-'a']==q){
g[p][ch-'a']=nq;
p=pre[p];
}
last=nq;
size[last]++;
return;
}
return;
}
int np=++tot;
size[np]=1;
step[np]=step[last]+1;
int p=last;
while (p&&g[p][ch-'a']==0){
g[p][ch-'a']=np;
p=pre[p];
}
if (!p) pre[np]=1;
else{
int q=g[p][ch-'a'];
if (step[q]==step[p]+1) pre[np]=q;
else{
int nq=++tot;
step[nq]=step[p]+1;
pre[nq]=pre[q];
pre[q]=nq;
int i;
fo(i,0,26) g[nq][i]=g[q][i];
pre[np]=nq;
while (p&&g[p][ch-'a']==q){
g[p][ch-'a']=nq;
p=pre[p];
}
}
}
last=np;
}
bool cmp(int a,int b){
if (step[a]<step[b]) return 1;
else if (step[a]==step[b]&&a<b) return 1;
else return 0;
}
int main(){
//freopen("word4.in","r",stdin);freopen("3127.out","w",stdout);
scanf("%d",&n);
last=tot=1;
fo(i,1,n){
s[++top]=get();
insert(s[top]);
while (1){
ch=getchar();
if (ch<'a'||ch>'z') break;
s[++top]=ch;
insert(s[top]);
}
s[++top]='a'+26;
last=1;
}
fo(i,1,tot) id[i]=i;
sort(id+1,id+tot+1,cmp);
fd(i,tot,1)
if (pre[id[i]]>1) size[pre[id[i]]]+=size[id[i]];
j=1;
fo(i,1,top){
if (s[i]=='a'+26){
printf("%d\n",size[j]);
j=1;
}
else j=g[j][s[i]-'a'];
}
}