Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //#define _GLIBCXX_DEBUG
- #define _CRT_SECURE_NO_WARNINGS
- #include <bits/stdc++.h>
- #define FAST_ALLOCATOR_MEMORY 2e8
- #ifdef FAST_ALLOCATOR_MEMORY
- int allocator_pos = 0;
- char allocator_memory[(int)FAST_ALLOCATOR_MEMORY];
- inline void * operator new ( size_t n ) {
- char *res = allocator_memory + allocator_pos;
- allocator_pos += n;
- assert(allocator_pos <= (int)FAST_ALLOCATOR_MEMORY);
- return (void *)res;
- }
- inline void operator delete ( void * ) noexcept { }
- //inline void * operator new [] ( size_t ) { assert(0); }
- //inline void operator delete [] ( void * ) { assert(0); }
- #endif
- using namespace std;
- typedef long long ll;
- typedef pair<int, int> pii;
- typedef vector<int> vi;
- typedef long double ld;
- #define mk make_pair
- #define inb push_back
- #define X first
- #define Y second
- #define all(v) v.begin(), v.end()
- #define sqr(x) (x) * (x)
- #define TIME 1.0 * clock() / CLOCKS_PER_SEC
- #define y1 AYDARBOG
- //continue break pop_back return
- int solve();
- int main()
- {
- //ios_base::sync_with_stdio(0);
- //cin.tie(0);
- #define TASK "lzss"
- #ifndef _DEBUG
- //freopen(TASK".in", "r", stdin), freopen(TASK".out", "w", stdout);
- #endif
- solve();
- #ifdef _DEBUG
- fprintf(stderr, "\nTIME: %.3f\n", TIME);
- #endif
- }
- const int STRSZ = (int)2e5 + 7;
- //read str
- char buf[STRSZ];
- string get_str()
- {
- scanf(" %s", buf);
- return string(buf);
- }
- vi buildSuffArray (string &s, int n)
- {
- int sz = 256;
- vi p(n), c(n), cnt(sz);
- for (int i = 0; i < n; ++i)
- ++cnt[s[i]];
- for (int i = 1; i < sz; ++i)
- cnt[i] += cnt[i - 1];
- for (int i = n - 1; i >= 0; --i)
- p[--cnt[s[i]]] = i;
- sz = 1;
- c[p[0]] = 0;
- for (int i = 1; i < n; ++i)
- {
- if (s[p[i]] != s[p[i - 1]])
- ++sz;
- c[p[i]] = sz - 1;
- }
- vi pn(n), cn(n);
- for (int h = 0; (1 << h) < n; ++h)
- {
- cnt.assign(sz, 0);
- for (int i = 0; i < n; ++i)
- pn[i] = (p[i] - (1 << h) >= 0) ? (p[i] - (1 << h)) : (p[i] - (1 << h) + n);
- for (int i = 0; i < n; ++i)
- ++cnt[c[pn[i]]];
- for (int i = 1; i < sz; ++i)
- cnt[i] += cnt[i - 1];
- for (int i = n - 1; i >= 0; --i)
- p[--cnt[c[pn[i]]]] = pn[i];
- sz = 1;
- cn[p[0]] = 0;
- for (int i = 1; i < n; ++i)
- {
- int m1 = (p[i] + (1 << h)) % n;
- int m2 = (p[i - 1] + (1 << h)) % n;
- if (c[p[i]] != c[p[i - 1]] || c[m1] != c[m2])
- ++sz;
- cn[p[i]] = sz - 1;
- }
- if (sz == n)
- {
- return p;
- }
- swap(c, cn);
- }
- return p;
- }
- vi buildLCP (string &s, int n, vi& sa)
- {
- vi lcp(n);
- int l = 0;
- vi pos(n);
- for (int i = 0; i < n; ++i)
- {
- pos[sa[i]] = i;
- }
- for (int i = 0; i < n; ++i)
- {
- if (pos[i] == n - 1)
- {
- l = 0;
- continue;
- }
- l = max(l - 1, 0);
- int j = sa[pos[i] + 1];
- while (max(i, j) + l < n && s[i + l] == s[j + l] && s[i + l] != '$')
- ++l;
- lcp[pos[i]] = l;
- }
- return lcp;
- }
- struct SegmentTree
- {
- int n;
- vi t;
- SegmentTree() {};
- SegmentTree(vi &a)
- {
- n = a.size();
- t.resize(4 * n);
- build(0, 0, n - 1, a);
- }
- void build(int v, int tl, int tr, vi& a)
- {
- if (tl == tr)
- {
- t[v] = a[tl];
- return;
- }
- int tm = tl + tr >> 1;
- build(2 * v + 1, tl, tm, a);
- build(2 * v + 2, tm + 1, tr, a);
- t[v] = min(t[2 * v + 1], t[2 * v + 2]);
- }
- int slide_left(int v, int tl, int tr, int l, int r, int val)
- {
- if (tl > r || tr < l || t[v] >= val)
- return -1;
- if (tl == tr)
- return tl;
- int tm = tl + tr >> 1;
- int rans = slide_left(2 * v + 2, tm + 1, tr, l, r, val);
- return (rans == -1) ? slide_left(2 * v + 1, tl, tm, l, r, val) : rans;
- }
- int slide_right(int v, int tl, int tr, int l, int r, int val)
- {
- if (tl > r || tr < l || t[v] >= val)
- return -1;
- if (tl == tr)
- return tl;
- int tm = tl + tr >> 1;
- int lans = slide_right(2 * v + 1, tl, tm, l, r, val);
- return (lans == -1) ? slide_right(2 * v + 2, tm + 1, tr, l, r, val) : lans;
- }
- };
- struct Node
- {
- int x;
- Node *l, *r;
- Node() { x = 0, l = NULL, r = NULL; };
- Node(int x) : x(x), l(NULL), r(NULL) {};
- Node(int x, Node *l, Node *r) : x(x), l(l), r(r) {};
- };
- int get_x(Node *t)
- {
- if (!t)
- return 0;
- return t->x;
- }
- struct PersistentSegmentTree
- {
- int n;
- vector<Node*> tv;
- PersistentSegmentTree() {};
- PersistentSegmentTree(int _n)
- {
- n = _n;
- Node *r = new Node();
- tv.inb(r);
- tv.back() = build(tv.back(), 1, n);
- }
- Node *build(Node *t, int tl, int tr)
- {
- if (tl == tr)
- {
- return new Node();
- }
- t->l = new Node();
- t->r = new Node();
- int tm = tl + tr >> 1;
- return new Node(0, build(t->l, tl, tm), build(t->r, tm + 1, tr));
- }
- void upd(int pos)
- {
- Node *r = new Node();
- r = update(tv.back(), 1, n, pos);
- tv.inb(r);
- }
- Node *update(Node *t, int tl, int tr, int pos)
- {
- if (tl == tr)
- {
- return new Node(t->x + 1, 0, 0);
- }
- int tm = tl + tr >> 1;
- if (tl <= pos && pos <= tm)
- {
- Node *nn = update(t->l, tl, tm, pos);
- return new Node(get_x(nn) + get_x(t->r), nn, t->r);
- }
- else
- {
- Node *nn = update(t->r, tm + 1, tr, pos);
- return new Node(get_x(t->l) + get_x(nn), t->l, nn);
- }
- }
- int get_res(int l, int r)
- {
- return get(tv[r + 1], 1, n, r + 1, n) - get(tv[l], 1, n, r + 1, n);
- }
- int get(Node *t, int tl, int tr, int l, int r)
- {
- if (tr < l || tl > r)
- return 0;
- if (l <= tl && tr <= r)
- return t->x;
- int tm = tl + tr >> 1;
- return get(t->l, tl, tm, l, r) + get(t->r, tm + 1, tr, l, r);
- }
- };
- vi calcnxt(vi &c, vi &a)
- {
- int n = a.size();
- vi q(n);
- for (int i = 0; i < n; ++i)
- {
- q[i] = c[a[i]];
- }
- vi lst(n + 2, -1);
- vi nxt(n, n);
- for (int i = 0; i < n; ++i)
- {
- if (lst[q[i]] != -1)
- {
- nxt[lst[q[i]]] = i;
- }
- lst[q[i]] = i;
- }
- return nxt;
- }
- int solve()
- {
- string s, cur;
- int k;
- scanf("%d", &k);
- for (int i = 0; i < k; ++i)
- {
- cur = get_str();
- s += cur;
- s.inb('$');
- }
- int n = s.size();
- vi col(n);
- int dolc = 0;
- for (int i = 0; i < n; ++i)
- {
- col[i] = dolc;
- if (s[i] == '$')
- {
- ++dolc;
- }
- }
- vi sa = buildSuffArray(s, n);
- vi lcp = buildLCP(s, n, sa);
- vi ans(k + 1);
- vi nxt = calcnxt(col, sa);
- SegmentTree Tlcp = SegmentTree(lcp);
- PersistentSegmentTree Tnxt = PersistentSegmentTree(n);
- for (int i = 0; i < n; ++i)
- {
- Tnxt.upd(nxt[i]);
- }
- for (int i = 0; i < n; ++i)
- {
- if (!lcp[i])
- continue;
- int l = Tlcp.slide_left(0, 0, n - 1, 0, i, lcp[i]) + 1;
- int r = Tlcp.slide_right(0, 0, n - 1, i, n - 1, lcp[i]);
- int cnt = Tnxt.get_res(l, r);
- ans[cnt] = max(ans[cnt], lcp[i]);
- }
- for (int i = k - 1; i >= 2; --i)
- ans[i] = max(ans[i + 1], ans[i]);
- for (int i = 2; i <= k; ++i)
- printf("%d\n", ans[i]);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement