CF1037H Security

Description

给定一个文本串 \(s\) 和询问次数 \(q\) ,每次给定小文本串 \(t\) 和一个区间 \(l\)\(r\) ,求一个字典序尽可能小的 \(s ^ {'}\) 使得是 \(s\) 的子串并且字典序严格大于 \(t\)

\(|s|,\ \sum |t| \leq 2 \cdot 10 ^ 5,\ \ q\leq 2\ cdot 10 ^ 5\)

Solution

好像对 \(s ^ {'}\) 的要求有点多,那就以最麻烦的子串作为出发条件。

会发现这题能和 你的名字 套路极度地像。同样,先考虑询问全是 \(s\) 全串怎么办。

situation 1

既然要求字典序必须要严格大于 \(t\) 但是最小,所以答案要尽可能贴近 \(t\) 的样子,就相当于 \(t\) 的一个前缀加上一个 \(s\) 上有转移的,加完比 \(t\) 大的字符。

所以对 \(s\) 建立 \({\rm SAM}\) ,然后我们直接把 \(t\) 丢上去跑匹配,匹配不上就看能不能加一个更大的字符(如果 \(t\) 也是 \(s\) 的子串就看能不能额外加一个字符),如果没有就往前一位上再找,假如这样子还没有答案那肯定就是无解了。

situation 2

如果是区间的话,发现我们好像需要 \(endpos\) ,不然可能一些本不在区间内的位置会匹配上。

那就还是用线段树合并解决 \(endpos\) 问题,每次找匹配,找字符都查询一遍是否合法,准确点是左端点在 \(L\) 右边,右端点在 \(R\) 左边才对。

插一嘴

刚想着要继续说什么,但是发现这样子就已经做完了。。甚至感觉 \({\rm SAM}\) 有点算是大材小用了吗。。

不!

这是线段树合并维护 \(endpos\) 的板子(迫真

Code

Code

/*

*/
#include 
using namespace std;
typedef long long ll;
const int N = 4e5 + 10, M = 4e6 + 10;
int rt[N], tot, ls[M], rs[M], nxt[N];
inline int read() {
    char ch = getchar();
    int s = 0, w = 1;
    while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
    while (isdigit(ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar();}
    return s * w;
}
inline void modify(int &now, int lt, int rt, int it) {
    if (!now) now = ++tot;
    if (lt == rt) return ;
    int mid = (lt + rt) >> 1;
    if (it <= mid) modify(ls[now], lt, mid, it);
    else modify(rs[now], mid + 1, rt, it);
}
inline bool query(int now, int lt, int rt, int L, int R) {
    if (!now) return 0;
    if (L <= lt && rt <= R) return 1;
    int mid = (lt + rt) >> 1, res = 0, ret = 0;
    if (L <= mid) res = query(ls[now], lt, mid, L, R);
    if (R > mid) ret = query(rs[now], mid + 1, rt, L, R);
    return res | ret;
}
inline int merge(int u, int v, int lt, int rt) {
    if (!u) return v;
    if (!v) return u;
    if (lt == rt) return u | v;
    int mid = (lt + rt) >> 1, w = ++tot;
    ls[w] = merge(ls[u], ls[v], lt, mid);
    rs[w] = merge(rs[u], rs[v], mid + 1, rt);
    return w;
}
struct SAM {
    int n, cnt, las, len[N], link[N], ch[N][26];
    char s[N]; int tong[N], rk[N], mx[N];
    inline void init() {
        cnt = las = 1;
        memset(ch[1], 0, sizeof(ch[1]));
    }
    inline void SAM_stru(int c) {
        int cur = ++cnt, p = las;
        memset(ch[cur], 0, sizeof(ch[cur]));
        las = cur;
        len[cur] = len[p] + 1;
        while (p && !ch[p][c]) ch[p][c] = cur, p = link[p];
        if (!p) {link[cur] = 1; return ;}
        int q = ch[p][c];
        if (len[p] + 1 == len[q]) {link[cur] = q; return ;}
        int clo = ++cnt;
        link[clo] = link[q]; len[clo] = len[p] + 1;
        link[q] = link[cur] = clo;
        memcpy(ch[clo], ch[q], sizeof(ch[clo]));
        while (p && ch[p][c] == q) ch[p][c] = clo, p = link[p];
    }
    inline void Tong_sort() {
        for (int i = 1; i <= cnt; ++i) ++tong[len[i]];
        for (int i = 1; i <= cnt; ++i) tong[i] += tong[i - 1];
        for (int i = 1; i <= cnt; ++i) rk[tong[len[i]]--] = i;
        for (int i = cnt, v, u; i >= 1; --i) {
            v = rk[i]; u = link[v];
            rt[u] = merge(rt[u], rt[v], 0, n - 1);
        }
    }
} s, t;
inline void mian() {
    int l = read() - 1, r = read() - 1;
    scanf("%s", t.s); t.n = strlen(t.s);
    int v = 1, it = 0;
    for (int i = 0, c; i <= t.n; ++i, it = i) {
        nxt[i] = -1;
        c = t.s[i] - 'a';
        for (int j = max(c + 1, 0), u; j < 26; ++j) {
            u = s.ch[v][j];
            if (u && query(rt[u], 0, s.n - 1, l + i, r)) {
                nxt[i] = j; break;
            }
        }
        if (i == t.n || !s.ch[v][c] || !query(rt[s.ch[v][c]], 0, s.n - 1, l + i, r)) break;
        v = s.ch[v][c];
    }
    while (~it && nxt[it] == -1) --it;
    if (it == -1) return printf("-1\n"), void();
    for (int i = 0; i < it; ++i) cout << t.s[i];
    cout << (char)(nxt[it] + 'a') << "\n";
}
int main() {
    scanf("%s", s.s); s.n = strlen(s.s); s.init();
    for (int i = 0; i < s.n; ++i) {
        s.SAM_stru(s.s[i] - 'a');
        modify(rt[s.las], 0, s.n - 1, i);
    }
    s.Tong_sort();
    int T = read();
    while (T--) mian();
    return 0;
}

posted @ 2022-02-18 20:50  Illusory_dimes  阅读(14)  评论(0编辑  收藏  举报