BZOJ - 3172
题目中的文章是由所有单词拼出来的,但是单词直接互相独立
首先单词都丢进AC自动机,然后一个个跑匹配
每一次更新\(fail\)树上一段路径前缀的节点即可
事实上就是在哪里放一个1,按次向根累加就能得到答案
int n;
int l;
string s[N];
int End[N];
const int SIZE=N;
int trie[N][26],fail[N],cnt;
int Insert(string &s){
int p=0;
rep(i,0,s.size()-1) {
int x=s[i]-'a';
if(!trie[p][x]) trie[p][x]=++cnt;
p=trie[p][x];
}
return p;
}
int line[SIZE],Ans[SIZE],lc;
void Build(){
static queue <int> que;
rep(i,0,25) if(trie[0][i]) que.push(trie[0][i]);
while(!que.empty()){
int u=que.front(); que.pop();
line[++lc]=u;
rep(i,0,25) {
int &v=trie[u][i];
if(v) {
que.push(v);
fail[v]=trie[fail[u]][i];
} else v=trie[fail[u]][i];
}
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
rep(i,1,n) {
cin>>s[i];
End[i]=Insert(s[i]);
}
Build();
rep(i,1,n){
int p=0;
rep(j,0,s[i].size()-1) {
p=trie[p][s[i][j]-'a'];
Ans[p]++;
}
}
drep(i,lc,1) Ans[fail[line[i]]]+=Ans[line[i]];//利用广搜序累和
rep(i,1,n) printf("%d\n",Ans[End[i]]);
}