题解
- 我们可以考虑从大到小枚举height,然后按顺序每一次将其两边的后缀集合合并,用并查集实现
- 这样我们每一次合并的后缀集合的组合一定满足它们的lcp会大于等于height[i],这两个集合的合并对任意r<= h[i]的答案都有其大小乘积的贡献
- 最大值同样维护即可,注意由于可能有负数,所以可以再维护一个最小值
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <algorithm>
4 #define ll long long
5 using namespace std;
6 const ll N=300010,inf=5e18;
7 ll n,t[N],t2[N],sa[N],rank[N],height[N],c[N],a[N],fa[N],cnt[N],mx[N],Mx[N],Mn[N],size[N];
8 char s[N];
9 bool cmp(ll x,ll y) { return height[x]>height[y]; }
10 ll find(ll x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
11 void get_SA()
12 {
13 ll l='z',*x=t,*y=t2;
14 for (ll i=0;i<=l;i++) c[i]=0;
15 for (ll i=1;i<=n;i++) c[x[i]=s[i]]++;
16 for (ll i=1;i<=l;i++) c[i]+=c[i-1];
17 for (ll i=n;i>=1;i--) sa[c[x[i]]--]=i;
18 for (ll k=1;k<n;k<<=1)
19 {
20 ll p=0;
21 for (ll i=n-k+1;i<=n;i++) y[++p]=i;
22 for (ll i=1;i<=n;i++)if(sa[i]>k) y[++p]=sa[i]-k;
23 for (ll i=0;i<=l;i++) c[i]=0;
24 for (ll i=1;i<=n;i++) c[x[y[i]]]++;
25 for (ll i=1;i<=l;i++) c[i]+=c[i-1];
26 for (ll i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i];
27 swap(x,y),p=x[sa[1]]=1;
28 for (ll i=2;i<=n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
29 if (p>=n) break;
30 l=p;
31 }
32 for (ll i=1;i<=n;i++) rank[sa[i]]=i;
33 ll k=0;
34 for (ll i=1;i<=n;i++)
35 {
36 ll j=sa[rank[i]+1];
37 if (!j) continue;
38 if (k) k--;
39 while (s[i+k]==s[j+k]) k++;
40 height[rank[i]]=k;
41 }
42 for (ll i=1;i<=n;i++) a[i]=i;
43 sort(a+1,a+n,cmp);
44 }
45 int main()
46 {
47 scanf("%lld",&n); for (ll i=0;i<=n;i++) fa[i]=i;
48 scanf("%s",s+1),get_SA();
49 for (ll i=1;i<=n;i++) scanf("%lld",&Mx[rank[i]]),size[rank[i]]=1,mx[i-1]=-inf,Mn[rank[i]]=Mx[rank[i]];
50 for (ll i=1;i<n;i++)
51 {
52 ll x=find(a[i]),y=find(a[i]+1);
53 cnt[height[a[i]]]+=size[x]*size[y],mx[height[a[i]]]=max(mx[height[a[i]]],max(Mn[x]*Mn[y],Mx[x]*Mx[y])),Mn[x]=min(Mn[x],Mn[y]),Mx[x]=max(Mx[x],Mx[y]),size[x]+=size[y],fa[y]=x;
54 }
55 for (ll i=n-2;i>=0;i--) cnt[i]+=cnt[i+1],mx[i]=max(mx[i],mx[i+1]);
56 for (ll i=0;i<n;i++) printf("%lld %lld
",cnt[i],cnt[i]?mx[i]:0);
57 }