1. 程式人生 > >【SDOI2016】【BZOJ4516】生成魔咒

【SDOI2016】【BZOJ4516】生成魔咒

【題目連結】

【前置技能】

  • 字尾樹

【題解】

  • 要求支援向字串後加一個字元,詢問字串中本質不同的子串的個數。
  • 考慮建立原串的反串的字尾樹,新出現的反串的字尾對於答案的貢獻為dep[pos]dep[fa[pos]]dep[pos] - dep[fa[pos]]。每次插入的時候維護一下答案即可。

【程式碼】

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL  long long
#define MAXN    100010
using namespace std;
int n;
LL ans;
template <typename T> void chkmin(T &x, T y){x = min(x, y);} template <typename T> void chkmax(T &x, T y){x = max(x, y);} template <typename T> void read(T &x){ x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();
} while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();} x *= f; } struct Suffix_Automaton{ struct info{int fa, dep, tag; map <int, int> son;}a[MAXN * 2]; int cnt, root, last; int create(int d){ ++cnt; a[cnt].dep = d; return cnt; } void
extend(int ch){ int p = last, np = create(a[p].dep + 1); while (!a[p].son[ch]) { a[p].son[ch] = np; p = a[p].fa; } if (a[p].son[ch] == np) a[np].fa = root; else { int q = a[p].son[ch]; if (a[q].dep == a[p].dep + 1) a[np].fa = q; else { int nq = create(a[p].dep + 1); a[nq].son = a[q].son; a[nq].fa = a[q].fa; a[q].fa = a[np].fa = nq; while (a[p].son[ch] == q){ a[p].son[ch] = nq; p = a[p].fa; } } } ans += a[np].dep - a[a[np].fa].dep; last = np; } }SAM; int main(){ read(n); for (int i = 1; i <= n; ++i){ int t; read(t); SAM.extend(t); printf("%lld\n", ans); } return 0; }