【回文自动机】 HDU 5394 Trie in Tina Town
题意:按要求建一棵树,求树上的价值=sum(len*cnt),len为回文长度,cnt为该回文在树上出现了多少次
思路:建好树从0开始往下跑就可以了,每跑完一条链,就回溯下。
代码:
#pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; typedef long long ll; typedef pair<int,int> pii; struct Node { int p, cur, c, nxt, last; Node () { } Node (int _p, int _cu, int _c, int _n, int _l) { p = _p; cur = _cu; c = _c; nxt = _n, last = _l; } }; const int MAX_N = 2000007; const int SIG = 4; struct PTree { int nxt[MAX_N][SIG], fail[MAX_N], len[MAX_N], S[MAX_N]; int last, n, p; ll lenCnt[MAX_N]; int newNode (int l) { memset(nxt[p], 0, sizeof nxt[p]); len[p] = l; lenCnt[p] = 0; return p++; } void init() { p = last = n = 0; newNode(0), newNode(-1); S[n] = -1; fail[0] = 1; } int getFail(int x) { while (S[n - len[x] - 1] != S[n]) x = fail[x]; return x; } Node add(int c, ll &ans) { c -= 'a'; S[++n] = c; int cur = getFail(last); Node now = Node(p, cur, c, nxt[cur][c], last); if (!nxt[cur][c]) { int now = newNode(len[cur] + 2); fail[now] = nxt[getFail(fail[cur])][c]; nxt[cur][c] = now; lenCnt[now] = lenCnt[fail[now]] + len[now]; } last = nxt[cur][c]; ans += lenCnt[last]; return now; } void pop(Node pre) { --n; p = pre.p, last = pre.last, nxt[pre.cur][pre.c] = pre.nxt; } }; struct Edge { int v, ch, nxt; Edge () { } Edge(int _v, int _ch, int _n) { v = _v; ch = _ch; nxt = _n; } }; Edge E[MAX_N]; int head[MAX_N], ecnt; PTree A; ll ans; void Clear(int n) { ecnt = 0; memset(head, -1, sizeof head); } void add(int u, int v, int w) { E[ecnt] = Edge(v, w, head[u]); head[u] = ecnt++; } void dfs(int u) { for (int i = head[u]; ~i; i = E[i].nxt) { int v = E[i].v, ch = E[i].ch; Node pre = A.add(ch, ans); dfs(v); A.pop(pre); } } int n; int main() { int T; scanf("%d", &T); while (T-- > 0) { scanf("%d", &n); int x; Clear(n); char s[2]; for (int i = 1; i <= n; ++i) { scanf("%s%d", s, &x); add(x, i, s[0]); } ans = 0; A.init(); dfs(0); printf("%I64d\n", ans); } return 0; }