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;
}
View Code

 

posted @ 2017-11-23 23:01  19992147  阅读(128)  评论(0编辑  收藏  举报