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;
}
posted @ 2022-07-06 21:48  Prgl  阅读(21)  评论(0)    收藏  举报