CF1037H. Security($sam$,线段树)

CF1037H. Security

\(Description\)

给定字符串 \(S\),有 \(m\) 组询问,每组询问有 \(l, \ r, \ T\),输出 \(S[l..r]\) 中字典序最小且严格大于 \(T\) 的子串。

\(Data \ Constraint\)

\(|S|, \ m, \ \sum{|T|} \leq 2 \times 10^5\)

考点

\(sam\),线段树

\(Solution\)

考虑满足条件的子串大概是什么样子的,不难想到可以表示为 \(A + c\)\(A\)\(T\) 的前缀。

由于要求字典序最小,所以显然 \(c\) 后不需要再添加任何字符,并且 \(|A|\) 最大。

所以我们对于原串 \(S\) 建出 \(sam\),然后对于询问串 \(T\),在 \(sam\) 上匹配,由于要求是区间 \([l, \ r]\) 的子串,所以对于 \(sam\) 上的每个状态,求出其 \(endpos\) 集合,设当前 \(T\) 匹配到第 \(k\) 位,那么 \(endpos\) 需包含 \([l + k - 1, \ r]\) 中至少一个,线段树合并可以简单维护。

按匹配顺序倒着求答案(\(|A|\) 最大),枚举 \(c\) 判断即可(注意通过 \(c\) 转移到的状态的 \(endpos\) 也需要满足条件),时间复杂度 \(O(26 n \log{n})\)

\(Code\)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define N 200000

#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)

void read(int &x) {
    char ch = getchar(); x = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
}


char ch[N + 1];

int n, m, rt[N + 1];

struct Tree {
    int sz[N << 5], lson[N << 5], rson[N << 5], tot;
    Tree() { tot = 0; }
    void Add(int &t, int l, int r, int k) {
        if (! t) t = ++ tot;
        ++ sz[t];
        if (l == r) return;
        int mid = l + r >> 1;
        k <= mid ? Add(lson[t], l, mid, k) : Add(rson[t], mid + 1, r, k);
    }
    int Merge(int u, int v, int l, int r) {
        if (! u || ! v) return u | v;
        if (l == r) return sz[++ tot] = sz[u] + sz[v], tot;
        int mid = l + r >> 1, cur = ++ tot;
        sz[cur] = sz[u] + sz[v];
        lson[cur] = Merge(lson[u], lson[v], l, mid);
        rson[cur] = Merge(rson[u], rson[v], mid + 1, r);
        return cur;
    }
    int Find(int t, int l, int r, int x, int y) {
        if (! t) return 0;
        if (l == r) return l;
        int mid = l + r >> 1;
        if (x <= l && r <= y)
            return sz[lson[t]] ? Find(lson[t], l, mid, x, y) : Find(rson[t], mid + 1, r, x, y);
        int d = 0;
        if (x <= mid && (d = Find(lson[t], l, mid, x, y)))
            return d;
        if (y > mid && (d = Find(rson[t], mid + 1, r, x, y)))
            return d;
        return 0;
    }
} tr;

int ans1, ans2, Len, L, R;

struct SAM {
    struct State { int next[26], len, link; };
    State st[N << 1];
    int sz, last;

    SAM() { sz = last = 0, st[0].len = 0, st[0].link = -1; }

    void Extend(char c, int endpos) {
        int cur = ++ sz, p = last, c0 = c - 'a';
        st[cur].len = st[p].len + 1;
        tr.Add(rt[cur], 1, n, endpos);
        while (p >= 0 && ! st[p].next[c0]) st[p].next[c0] = cur, p = st[p].link;
        if (p < 0)
            st[cur].link = 0;
        else {
            int q = st[p].next[c0];
            if (st[p].len + 1 == st[q].len)
                st[cur].link = q;
            else {
                int clone = ++ sz;
                st[clone] = st[q], st[clone].len = st[p].len + 1;
                while (p >= 0 && st[p].next[c0] == q)
                    st[p].next[c0] = clone, p = st[p].link;
                st[cur].link = st[q].link = clone;
            }
        }
        last = cur;
    }
    int d[N << 1], sta[N << 1];
    void Build_ep() {
        fo(i, 1, sz) ++ d[st[i].link];
        int t = 0;
        fo(i, 1, sz) if (! d[i])
            sta[ ++ t ] = i;
        for (int h = 0, x = 0; h ++ < t; ) {
            if (! -- d[st[x = sta[h]].link])
                sta[ ++ t ] = st[x].link;
            rt[st[x].link] = tr.Merge(rt[st[x].link], rt[x], 1, n);
        }
    }
    bool Find(int u, int c0, int k) {
        if (c0 > 25) return 0;
        int v = 0;
        fo(i, c0, 25) if (st[u].next[i]) {
            v = st[u].next[i];
            if (tr.Find(rt[v], 1, n, L + k, R))
                return ans1 = k, ans2 = i, 1;
        }
        return 0;
    }
    bool Solve(int u, int k) {
        if (u && ! tr.Find(rt[u], 1, n, L + k - 1, R))
            return 0;
        if (k == Len)
            return Find(u, 0, k);
        if (k == R - L)
            return Find(u, ch[k + 1] - 'a' + 1, k);
        int v = st[u].next[ch[k + 1] - 'a'];
        if (v && Solve(v, k + 1))
            return 1;
        return Find(u, ch[k + 1] - 'a' + 1, k);
    }
} sam;

int main() {
    freopen("security.in", "r", stdin);
    freopen("security.out", "w", stdout);

    scanf("%s\n", ch + 1); n = strlen(ch + 1);
    read(m);

    fo(i, 1, n)
        sam.Extend(ch[i], i);
    sam.Build_ep();

    fo(Case, 1, m) {
        read(L), read(R), scanf("%s\n", ch + 1);
        ans1 = ans2 = 0, Len = strlen(ch + 1);
        if (! sam.Solve(0, 0))
            puts("-1");
        else {
            fo(i, 1, ans1) putchar(ch[i]);
            putchar((char) ans2 + 'a'); puts("");
        }
    }

    return 0;
}
posted @ 2020-12-22 20:08  buzzhou  阅读(41)  评论(0编辑  收藏  举报