luogu P4070 [SDOI2016]生成魔咒
题面传送门
首先如果最后一起搞那么拓扑排序一遍就好了。
但是这道题它有多次询问。
联合SAM本质就可以知道增加的数量就是\(len_p-len_{fa_p}\)
这个怎么理解呢?源点到每个点的路径数就是子串数且等于\(len\)
那么显然就可以了。
code:
#include<cstdio>
#include<cstring>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(x) x<<1
#define r(x) x<<1|1
#define N 200039
#define ll long long
#define ui unsigned int
using namespace std;
int n,m,k,x,y,z;ll ans;
struct SAM{
int fa[N],len[N],cnt=1,last=1,now,pus,cur,p;map<int,int> son[N];
I void insert(int x){
p=last;now=last=++cnt;len[now]=len[p]+1;
while(p&&!son[p][x]) son[p][x]=now,p=fa[p];
if(!p) return (void)(fa[now]=1,ans+=len[now]);
cur=son[p][x];if(len[cur]==len[p]+1) fa[now]=cur,ans+=len[now]-len[cur];
else{
len[pus=++cnt]=len[p]+1;fa[pus]=fa[cur];fa[cur]=fa[now]=pus;son[pus]=son[cur];ans+=len[now]-len[pus];
while(p&&son[p][x]==cur) son[p][x]=pus,p=fa[p];
}
}
}s;
int main(){
freopen("1.in","r",stdin);
register int i;scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&x),s.insert(x),printf("%lld\n",ans);
}