正题
题目链接:https://www.luogu.com.cn/problem/P4070
题目大意
长度为nnn的字符串,对于每个iii求字符串1∼i1\sim i1∼i部分有多少个不同的子串。
解题思路
对于整个串ans=∑i=1nn−i+1−heightians=\sum_{i=1}^nn-i+1-height_ians=∑i=1nn−i+1−heighti,考虑如何维护heightheightheight
往末尾加上一个字符会对heightheightheight造成很大影响,但是如果在字符串前面加上一个heightheightheight的话就不会对其他heightheightheight造成影响了。
所以先翻转字符串,问题变为每次在前面加上一个字符。
首先离线后缀排好序,然后每次加入一个字符时,我们用平衡树找已经插入的前驱和后继然后用STSTST表来求到他们的LCPLCPLCP(也就是更新后的heightheightheight)即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N=1e5+10;
int n,m,a[N],b[N],height[N],lg[N];
int c[N],sa[N],rk[N],x[N],y[N];
int f[20][N];long long ans;
set<int> s;
void Qsort(){for(int i=1;i<=m;i++)c[i]=0;for(int i=1;i<=n;i++)c[x[i]]++;for(int i=1;i<=m;i++)c[i]+=c[i-1];for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;return;
}
void SA(){for(int i=1;i<=n;i++)x[i]=a[i],y[i]=i;Qsort();for(int w=1;w<=n;w<<=1){int p=0;for(int i=n-w+1;i<=n;i++)y[++p]=i;for(int i=1;i<=n;i++)if(sa[i]>w)y[++p]=sa[i]-w;Qsort();swap(x,y);p=x[sa[1]]=1;for(int i=2;i<=n;i++)x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+w]==y[sa[i-1]+w])?p:++p;if(p==n)break;m=p;}return;
}
void Get_Height(){int k=0;for(int i=1;i<=n;i++)rk[sa[i]]=i;for(int i=1;i<=n;i++){if(rk[i]==1)continue;if(k)k--;int j=sa[rk[i]-1];while(i+k<=n&&j+k<=n&&a[i+k]==a[j+k])k++;height[rk[i]]=k;}return;
}
void RMQ(){lg[0]=-1;for(int i=1;i<=n;i++)lg[i]=lg[i/2]+1,f[0][i]=height[i];for(int i=1;i<19;i++)for(int j=1;j+(1<<i-1)<=n;j++)f[i][j]=min(f[i-1][j],f[i-1][j+(1<<i-1)]);return;
}
int LCP(int l,int r){l++;int z=lg[r-l+1];return min(f[z][l],f[z][r+1-(1<<z)]);
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[i]=a[i];}sort(b+1,b+1+n);m=unique(b+1,b+1+n)-b-1;for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+m,a[i])-b;for(int i=1;i<=n/2;i++)swap(a[i],a[n-i+1]);SA();Get_Height();RMQ();for(int i=n;i>=1;i--){s.insert(rk[i]);set<int>::iterator it=s.find(rk[i]);int k=0;if(it!=s.begin()){int p=*(--it);k=LCP(p,rk[i]);++it;}++it;if(it!=s.end()){int p=*it;k=max(k,LCP(rk[i],p));}ans+=n-i+1-k;printf("%lld\n",ans);}
}