P4248 [AHOI2013]差异
题目大意
给定一个长度为 \(n(1\le n\le5\cdot10^5)\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀。求 \(\sum_{1\le i<j\le n}len(T_i)+len(T_j)-2\times lcp(T_i,T_j)\) 。其中,\(len(a)\) 表示字符串 \(a\) 的长度,\(lcp(a,b)\) 表示字符串 \(a\) 和字符串 \(b\) 的最长公共前缀的长度。
思路
我们对 \(S\) 的反串建 \(sam\) ,其每个 \(np\) 类节点接受一个原串的后缀,对于串 \(a\) , \(b\) 。其各自所属节点在后缀树上的 \(lca\) 所接受的最长串即为 \(lcp(a,b)\) 。又注意到令后缀树上边的权值为子节点的 \(len\) 减去父节点的 \(len\) ,则所求式子可以表示为从 \(a\) 所在节点到 \(b\) 所在节点的路径长度,我们可以通过 \(dfs\) 计算每条边对答案的贡献即可轻易求出。
代码
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
//#define lc P*2
//#define rc P*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 500010;
struct Edge {
int to, cost;
};
string S;
vector<Edge>G[maxn * 3];
LL ans = 0;
int tot = 1, last = 1, nps[maxn * 3];
struct Node {
int len, fa;
int ch[26];
bool isnp;
}sam[maxn * 3];
void extend(char c)
{
int p = last, np = last = ++tot;
sam[np].len = sam[p].len + 1;
sam[np].isnp = true;
for (; p && !sam[p].ch[c]; p = sam[p].fa)
sam[p].ch[c] = np;
if (!p)
sam[np].fa = 1;
else
{
int q = sam[p].ch[c];
if (sam[q].len == sam[p].len + 1)
sam[np].fa = q;
else
{
int nq = ++tot;
sam[nq] = sam[q], sam[nq].len = sam[p].len + 1;
sam[nq].isnp = false;
sam[q].fa = sam[np].fa = nq;
for (; p && sam[p].ch[c] == q; p = sam[p].fa)
sam[p].ch[c] = nq;
}
}
}
void add_edge(int from, int to, int cost)
{
G[from].push_back(Edge{ to,cost });
G[to].push_back(Edge{ from,cost });
}
void dfs1(int v, int p)
{
nps[v] += sam[v].isnp;
for (auto& e : G[v])
{
if (e.to == p)
continue;
dfs1(e.to, v);
nps[v] += nps[e.to];
}
}
void dfs2(int v, int p)
{
for (auto& e : G[v])
{
if (e.to == p)
continue;
ans += (LL)nps[e.to] * (LL)(nps[1] - nps[e.to]) * (LL)e.cost;
dfs2(e.to, v);
}
}
void solve()
{
int N = S.length();
for (int i = N - 1; i >= 0; i--)
extend(S[i] - 'a');
for (int i = 2; i <= tot; i++)
add_edge(sam[i].fa, i, sam[i].len - sam[sam[i].fa].len);
dfs1(1, 0), dfs2(1, 0);
cout << ans << endl;
}
int main()
{
IOS;
cin >> S;
solve();
return 0;
}