Solution
考虑这个f(s)的含义,相当于对于每一个后缀而言,他能匹配的前缀的个数(不包含他自己)就是他的深度。反过来看,就是某一个前缀的出现次数。
那么考虑key(s)的含义,就是说对于两个相同的子串s[l1,r1] , s[l2 ,r2],他的贡献就是len - r2。
然后每加入一个点,par树上所对应的链会加上一个endpos,其他的增加一个定值,记录下来,然后就是查询一个链和,完了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct state{
int nex[26] , link , len;
}st[N * 2];
int last , scnt , endpos[N];
void init(){scnt = last = 1;}
void extend(int c,int suf){
int cur = ++scnt , p;endpos[suf] = cur;
st[cur].len = st[last].len + 1;
for (p = last ; p && !st[p].nex[c];p = st[p].link) st[p].nex[c] = cur;
if (!p) { st[cur].link = 1; }
else{
int q = st[p].nex[c];
if (st[q].len == st[p].len + 1){
st[cur].link = q;
}else{
int clone = ++scnt;
st[clone].len = st[p].len + 1;
memcpy(st[clone].nex , st[q].nex , sizeof (st[clone].nex) ) ;
st[clone].link = st[q].link;
st[cur].link = st[q].link = clone;
for (; p && st[p].nex[c] == q;p = st[p].link) st[p].nex[c] = clone;
}
}
last = cur;
}
struct E{
int to , nex;
}e[N * 2];int head[N * 2] , ecnt;
void adde(int fr,int to){e[++ecnt]=(E){to,head[fr]};head[fr] = ecnt;}
void addedge(int fr,int to){adde(fr,to);adde(to,fr);}
int fa[2 * N] , dfn[N * 2] , tdfn[N * 2] , top[N * 2] , dep[N * 2] , sz[N * 2] , son[N * 2] , clk;
void dfs1(int o){
sz[o] = 1;
for (int j = head[o];j;j=e[j].nex){
dep[e[j].to] = dep[o] + 1;
fa[e[j].to] = o;
dfs1(e[j].to);
sz[o] += sz[e[j].to];
if (!son[o] || sz[son[o]] < sz[e[j].to]) son[o] = e[j].to;
}
}
void dfs2(int o,int Top){
top[o] = Top;dfn[++clk] = o;tdfn[o] = clk;
if (son[o]) dfs2(son[o] , Top);
for (int j = head[o];j;j=e[j].nex)
if (e[j].to != son[o]){
dfs2(e[j].to , e[j].to);
}
}
#define mod 1000000007
int add(int x,int y){
x += y;
if (x >= mod) x -= mod;
return x;
}
struct Node{
int sum;
int tg , sumlen;
}tr[N * 8];
void up(int o){
tr[o].sum = add(tr[o<<1].sum , tr[o<<1|1].sum);
}
void down(int o){
if (tr[o].tg){
tr[o<<1].sum = add(tr[o<<1].sum , 1ll * tr[o].tg * tr[o<<1].sumlen % mod);
tr[o<<1].tg = add(tr[o<<1].tg , tr[o].tg);
tr[o<<1|1].sum = add(tr[o<<1|1].sum , 1ll * tr[o].tg * tr[o<<1|1].sumlen % mod);
tr[o<<1|1].tg = add(tr[o<<1|1].tg , tr[o].tg);
tr[o].tg = 0;
}
}
void build(int o,int l,int r){
if (l == r){
tr[o].sumlen = st[dfn[l]].len - st[st[dfn[l]].link].len;
return;
}
int mid = l + r >> 1;
build(o << 1 , l , mid);
build(o << 1 | 1 , mid + 1 , r);
tr[o].sumlen = add(tr[o<<1].sumlen , tr[o<<1|1].sumlen);
}
void modify(int o,int l,int r,int ql,int qr){
if (ql <= l && r <= qr){
tr[o].sum = add(tr[o].sum , tr[o].sumlen );
tr[o].tg = add(tr[o].tg , 1);
return;
}
int mid = l + r >> 1;
down(o);
if (ql <= mid) modify(o << 1 , l , mid , ql , qr);
if (mid < qr ) modify(o << 1 | 1 , mid + 1 , r , ql , qr);
up(o);
}
int query(int o,int l,int r,int ql,int qr){
if (ql <= l && r <= qr){
return tr[o].sum;
}
int mid = l + r >> 1 , ans = 0;
down(o);
if (ql <= mid) ans += query(o << 1 , l , mid , ql , qr);
if (mid < qr ) ans += query(o << 1 | 1 , mid + 1 , r , ql , qr);
return ans;
}
void Modify(int u,int v){
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u , v);
modify(1 , 1 , clk , tdfn[top[u]] , tdfn[u]);
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u , v);
modify(1 , 1 , clk , tdfn[u] , tdfn[v]);
}
int Query(int u,int v){
int ans = 0;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u , v);
ans = add(ans , query(1 , 1 , clk , tdfn[top[u]] , tdfn[u]) );
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u , v);
ans = add(ans , query(1 , 1 , clk , tdfn[u] , tdfn[v]) );
return ans;
}
int n , sum , res;
char s[N];
int main(){
init();
cin >> n;
scanf("%s",s+1);
for (int i = 1;i <= n;i++) extend(s[i] - 'a' , i);
for (int i = 2;i <= scnt;i++){
adde(st[i].link , i);
}
fa[1] = 1;dfs1(1);dfs2(1 , 1);
build(1 , 1 , clk);
for (int i = 1;i <= n;i++){
sum = add(sum , Query(1 , endpos[i]));
res = add(res , sum);
Modify(1 , endpos[i]);
printf("%d\n",res);
}
return 0;
}