题目大意:求所有后缀长度减去LCP长度的二倍。
思路:之前用后缀数组写过,但是做法并不是很直观。现在学了后缀树再来写一次,这次思路就很清晰了。
首先我们把字符串按照倒序插入到后缀树中。形成的后缀树有一个很好的性质,连个后缀节点的LCA就是这两个后缀的LCP的位置,LCA的len值自然就是两个后缀的LCP。
建好树之后,进行一次树形DP,统计出来每两个后缀的LCP长度,计入总答案。
这东西以后不用指针写了,简直DT死了。。
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1000010
using namespace std;
struct Complex{
Complex *tranc[26],*father;
int len,id,size;
}none,*nil = &none,*root,*last;
Complex mempool[MAX],*C = mempool;
Complex *NewComplex(int _,bool is_suffix)
{
static int cnt = 0;
C->id = ++cnt;
C->size = is_suffix;
fill(C->tranc,C->tranc + 26,nil);
C->father = nil;
C->len = _;
return C++;
}
void Pretreatment()
{
root = last = NewComplex(0,false);
}
char s[MAX];
inline void Add(int c)
{
Complex *np = NewComplex(last->len + 1,true),*p = last;
for(; p != nil && p->tranc[c] == nil; p = p->father) p->tranc[c] = np;
if(p == nil) np->father = root;
else {
Complex *q = p->tranc[c];
if(q->len == p->len + 1) np->father = q;
else {
Complex *nq = NewComplex(p->len + 1,false);
nq->father = q->father;
q->father = np->father = nq;
memcpy(nq->tranc,q->tranc,sizeof(q->tranc));
for(; p != nil && p->tranc[c] == q; p = p->father) p->tranc[c] = nq;
}
}
last = np;
}
int head[MAX],total;
int next[MAX],aim[MAX];
void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
long long sum = 0;
void DFS(int x,int last)
{
for(int i = head[x]; i; i = next[i]) {
DFS(aim[i],x);
mempool[x].size += mempool[aim[i]].size;
}
mempool[x].len -= mempool[last].len;
sum += (long long)mempool[x].size * (mempool[x].size - 1) * mempool[x].len;
}
int main()
{
Pretreatment();
scanf("%s",s);
int length = strlen(s);
for(int i = length - 1; ~i; --i)
Add(s[i] - 'a');
for(Complex *p = mempool + 1; p != C; ++p)
Add(p->father->id - 1,p->id - 1);
for(int i = head[0]; i; i = next[i]) DFS(aim[i],0);
cout << (long long)(length + 1) * length * (length - 1) / 2 - sum << endl;
return 0;
}