-
Notifications
You must be signed in to change notification settings - Fork 775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Addition: Palindromic Tree #205
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,58 @@ | ||||||||
/** | ||||||||
* Author: Ahmed Dardery | ||||||||
* Date: 2020-12-24 | ||||||||
* License: CC0 | ||||||||
* Source: https://codeforces.com/blog/entry/13959 | ||||||||
* Description: Builds a palindromic tree over a string | ||||||||
* 0 is the imaginary string, 1 is the empty string | ||||||||
* [2, n) are the palindromes, s.substr(pos[i], len[i]), occurs freq[i] | ||||||||
* fail[i] is the longest suffix palindrome of ith palindrome | ||||||||
* Time: O(n) | ||||||||
* Status: stress-tested | ||||||||
*/ | ||||||||
#pragma once | ||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indent with tabs (which will expand to 2 spaces in the pdf) |
||||||||
struct PalinTree { | ||||||||
const int A = 128; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const member isn't great, make it constexpr or move it outside or do |
||||||||
string str; | ||||||||
vi fail, len, pos, lz, freq; | ||||||||
vector<vi> nxt; | ||||||||
int n, cur; | ||||||||
|
||||||||
PalinTree(const string &s) : str(s) { | ||||||||
fail = len = pos = lz = freq = vi(sz(s) + 2); | ||||||||
nxt.resize(sz(s) + 2); | ||||||||
n = cur = fail[0] = fail[1] = 0; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fail[0] and fail[1] are automatically 0, and |
||||||||
addNode(-1, -1), addNode(0, 0); | ||||||||
rep(i, 0, sz(s)) addChar(i, s[i]); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(kactl doesn't use spaces in rep macro arguments except when they are long) |
||||||||
propagate(); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not all usages of palindromic trees need |
||||||||
} | ||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's squeeze this a bit by removing blank lines between methods |
||||||||
void addChar(int i, int c) { | ||||||||
int u = getFailure(cur, i); | ||||||||
int &ch = nxt[u][c]; | ||||||||
Comment on lines
+32
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
if (~ch) return (void) ++lz[cur = ch]; | ||||||||
int v = cur = ch = addNode(len[u] + 2, i - len[u] - 1); | ||||||||
fail[v] = len[v] == 1 ? 1 : nxt[getFailure(fail[u], i)][c]; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can use |
||||||||
} | ||||||||
|
||||||||
int addNode(int l, int p) { | ||||||||
nxt[n].assign(A, -1); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
and make nxt a vector<array<int, A>>; I think that should increase performance |
||||||||
len[n] = l, pos[n] = p, lz[n] = 1, freq[n] = 0; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
return n++; | ||||||||
} | ||||||||
|
||||||||
void propagate() { | ||||||||
for (int i = n - 1; ~i; --i) { | ||||||||
freq[i] += lz[i]; | ||||||||
lz[fail[i]] += lz[i]; | ||||||||
lz[i] = 0; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is set up for propagate being called multiple times, but I don't see the point of that since it's O(n) which matches the full tree construction? would it make sense to replace |
||||||||
} | ||||||||
} | ||||||||
|
||||||||
int getFailure(int u, int i) { | ||||||||
while (i <= len[u] || str[i] != str[i - len[u] - 1]) u = fail[u]; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this line goes past 63 chars, wrap it before |
||||||||
return u; | ||||||||
} | ||||||||
}; | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ \chapter{Strings} | |
\kactlimport{SuffixTree.h} | ||
\kactlimport{Hashing.h} | ||
\kactlimport{AhoCorasick.h} | ||
\kactlimport{PalindromicTree.h} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (it's a bit sad to have both PalindromicTree and Manacher, but I guess they kinda compute different things) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#include "../utilities/template.h" | ||
#include "../../content/strings/PalindromicTree.h" | ||
|
||
|
||
int main() { | ||
rep(alpha, 2, 27) { | ||
rep(t, 0, 10000) { | ||
int n = 1 + rand() % 30; | ||
string s(n, 0); | ||
rep(i, 0, n) { | ||
s[i] = char(rand() % alpha); | ||
} | ||
PalinTree tree(s); | ||
map<string, int> mp; | ||
vector<vi> dp(n+1, vi(n+1)); | ||
rep(i, 0, n+1) dp[0][i] = 1; | ||
rep(l, 1, n + 1) rep(i, 0, n - l + 1) { | ||
dp[l][i] = l<= 1 || (dp[l-2][i + 1] && s[i] == s[i + l - 1]); | ||
if (dp[l][i]) | ||
++mp[s.substr(i, l)]; | ||
} | ||
rep(i, 2, tree.n) { | ||
string sub = s.substr(tree.pos[i], tree.len[i]); | ||
int cnt = mp.find(sub)->second; | ||
assert(cnt == tree.freq[i]); | ||
mp.erase(sub); | ||
} | ||
assert(mp.empty()); | ||
} | ||
} | ||
cout << "Test passed!\n"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to explain the tree structure too. As I understand it
fail
is a tree parent pointer, but I'm not clear on when fail[i] is 0 and when it's 1.fail
isn't a great name,suf
orpar
may be better