bzoj1396
后缀自动机+线段树
今天比较颓。。。
既然只出现一次,那么就是right=1,于是我们预处理出每个点的right,然后看是否等于一,如果是就更新答案。
更新答案维护两个线段树,如果当前点在延伸[Min,Max]范围内,那么答案就是end-i+1,如果<Min,那么答案就是Min,于是我们维护end+1,再维护Min,end+1最后-i就行了。
#include<bits/stdc++.h> using namespace std; const int N = 5e5 + 5, inf = 0x3f3f3f3f; int n; int f[N << 1], c[N << 1], mp[N << 1], a[N << 1]; char s[N]; namespace SAM { struct node { int val, par; map<int, int> ch; } t[N << 1]; int last = 1, root = 1, sz = 1; int nw(int _) { t[++sz].val = _; return sz; } void extend(int c) { int p = last, np = nw(t[p].val + 1); while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par; if(!p) t[np].par = root; else { int q = t[p].ch[c]; if(t[q].val == t[p].val + 1) t[np].par = q; else { int nq = nw(t[p].val + 1); t[nq].ch = t[q].ch; t[nq].par = t[q].par; t[q].par = t[np].par = nq; while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par; } } f[np] = 1; mp[np] = t[np].val; last = np; } } using namespace SAM; struct Segment_Tree { int tree[N << 2], tag[N << 2]; Segment_Tree() { memset(tag, 0x3f3f, sizeof(tag)); memset(tree, 0x3f3f, sizeof(tree)); } void pushdown(int x) { tag[x << 1] = min(tag[x << 1], tag[x]); tag[x << 1 | 1] = min(tag[x << 1 | 1], tag[x]); tree[x << 1] = min(tree[x << 1], tag[x]); tree[x << 1 | 1] = min(tree[x << 1 | 1], tag[x]); tag[x] = inf; } void update(int l, int r, int x, int a, int b, int d) { if(l > b || r < a) return; if(l >= a && r <= b) { tree[x] = min(tree[x], d); tag[x] = min(tag[x], d); return; } pushdown(x); int mid = (l + r) >> 1; update(l, mid, x << 1, a, b, d); update(mid + 1, r, x << 1 | 1, a, b, d); tree[x] = min(tree[x << 1], tree[x << 1 | 1]); } int query(int l, int r, int x, int pos) { if(l == r) return tree[x]; pushdown(x); int mid = (l + r) >> 1; if(pos <= mid) return query(l, mid, x << 1, pos); else return query(mid + 1, r, x << 1 | 1, pos); } } A, B; int main() { scanf("%s", s + 1); n = strlen(s + 1); for(int i = 1; i <= n; ++i) extend(s[i] - 'a'); for(int i = 1; i <= sz; ++i) ++c[t[i].val]; for(int i = 1; i <= sz; ++i) c[i] += c[i - 1]; for(int i = 1; i <= sz; ++i) a[c[t[i].val]--] = i; for(int i = sz; i; --i) { f[t[a[i]].par] += f[a[i]]; mp[t[a[i]].par] = max(mp[t[a[i]].par], mp[a[i]]); } for(int i = 1; i <= sz; ++i) if(f[i] == 1) { int l = t[t[i].par].val, r = t[i].val; A.update(1, n, 1, mp[i] - l, mp[i], l + 1); B.update(1, n, 1, mp[i] - r + 1, mp[i] - l, mp[i] + 1); } for(int i = 1; i <= n; ++i) printf("%d\n", min(A.query(1, n, 1, i), B.query(1, n, 1, i) - i)); return 0; }