题目大意:求所有后缀长度减去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; }
时间: 2024-10-26 04:55:44