[AHOI2013]差異
阿新 • • 發佈:2021-08-05
考慮SAM是tire的集合物。
所以sam的父節點都是一個串的字尾。
所以我們反過來,再求\(LCA\)就是LCP了。
這個求和類似於一個路徑求和。
我們考慮每條邊的權值為\(len_p - len_{link_p}\)
#include<iostream> #include<cstdio> #include<cstring> #define ll long long #define N 500005 ll link[N << 1],ch[N << 1][30],f[N << 1],g[N << 1],len[N << 1]; ll siz[N << 1]; char a[N]; ll nod = 1,lst = 1; inline void insert(int c){ int p = lst,q = ++nod;lst = q; len[q] = len[p] + 1; siz[q] = 1; while(!ch[p][c] && p != 0){//向上找 ch[p][c] = q; p = link[p]; } if(p == 0) link[q] = 1; else{ int x = ch[p][c]; if(len[p] + 1 == len[x]){ link[q] = x; }else{ int y = ++ nod ;//複製一個新節點 link[y] = link[x]; link[x] = link[q] = y; len[y] = len[p] + 1; std::memcpy(ch[y],ch[x],sizeof(ch[x])); while(p != 0 && ch[p][c] == x){ ch[p][c] = y; p = link[p]; } } } } ll n,ans; struct P{ int to,next; }e[N << 2]; ll cnt,head[N << 1]; inline void add(int x,int y){ e[++cnt].to = y; e[cnt].next = head[x]; head[x] = cnt; } inline void dfs(ll u,ll f){ for(int i = head[u];i;i = e[i].next){ int v = e[i].to; if(v == f)continue; dfs(v,u); siz[u] += siz[v]; } if(u != 1) ans = ans + (len[u] - len[link[u]]) * (siz[u]) * (n - siz[u]); } int main(){ scanf("%s",a + 1); n = std::strlen(a + 1); for(int i = n;i >= 1;--i) insert(a[i] - 'a'); for(int i = 1;i <= nod;++i) add(link[i],i); dfs(1,0); std::cout<<ans<<std::endl; }