Codeforces 1037 H. Security

\(>Codeforces \space 1037\ H. Security<\)

题目大意 : 有一个串 \(S\)\(q\) 组询问,每一次给出一个询问串 \(T\) 和一个区间 \([l,r]\) ,要求找出 \(S\)\([l,r]\) 之间的子串中字典序大于 \(T\) 且最小的

\(1 \leq |S|\leq 10^5, 1\leq q \leq 2 \times 10^5\)

解题思路 :

其实这个题一点意思都没有,就是一个 \(sam\) + 线段树合并裸题..

但是某位不得了的指导大人近期 \(AC\) 了此题,于是我就去顺手做了一下

考虑每次把询问串在 \(sam\) 上匹配,对于每一个在 \(sam\) 上出现的 \(T\) 的合法前缀,大力算出能否在后面加一个字符满足比 \(T\) 大且在 \(L, R\) 区间

后者线段树合并维护即可

/*program by mangoyang*/
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int ch = 0, f = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
const int N = 1000005;
char s[N]; int n;
struct SegmentTree{
    int sz[N*25], lc[N*25], rc[N*25], size;
    inline void ins(int &u, int l, int r, int pos){
        if(!u) u = ++size;
        if(l == r) return (void) (sz[u]++);
        int mid = l + r >> 1;
        if(pos <= mid) ins(lc[u], l, mid, pos);
        else ins(rc[u], mid + 1, r, pos); sz[u] = sz[lc[u]] + sz[rc[u]];
    }
    inline int merge(int x, int y, int l, int r){
        if(!x || !y) return x + y;
        int o = ++size, mid = l + r >> 1;
        if(l == r) sz[o] = sz[x] + sz[y];
        else{
            lc[o] = merge(lc[x], lc[y], l, mid);
            rc[o] = merge(rc[x], rc[y], mid + 1, r);
            sz[o] = sz[lc[o]] + sz[rc[o]];
        }
        return o;
    }
    inline int query(int u, int l, int r, int L, int R){
        if(!u || l > r) return 0;
        if(l >= L && r <= R) return sz[u];
        int mid = l + r >> 1, res = 0;
        if(L <= mid) res += query(lc[u], l, mid, L, R);
        if(mid < R) res += query(rc[u], mid + 1, r, L, R); 
        return res;
    }
}Seg;
struct SaffixAutomaton{
    vector<int> g[N];
    int ch[N][26], dep[N], rt[N], fa[N], size, tail;
    inline SaffixAutomaton(){ size = tail = 1; }
    inline int newnode(int x){ return dep[++size] = x, size; }
    inline void ins(int c, int pos){
        int p = tail, np = newnode(dep[p] + 1);
        Seg.ins(rt[np], 1, n, pos);
        for(; !ch[p][c] && p; p = fa[p]) ch[p][c] = np;
        if(!p) return (void) (fa[np] = 1, tail = np);
        int q = ch[p][c];
        if(dep[q] == dep[p] + 1) fa[np] = q;
        else{
            int nq = newnode(dep[p] + 1); 
            fa[nq] = fa[q], fa[q] = fa[np] = nq;
            for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
            for(; ch[p][c] == q && p; p = fa[p]) ch[p][c] = nq;
        }tail = np;
    }
    inline void dfs(int u){
        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            dfs(v), rt[u] = Seg.merge(rt[u], rt[v], 1, n);
        }
    }
    inline void Prework(){ 
        for(int i = 1; i <= size; i++) g[fa[i]].push_back(i); dfs(1); 
    }
    inline void solve(char *s, int l, int r){
        int len = strlen(s + 1), p = 1, pos = 0, res = 0;
        for(int i = 1; i <= len + 1; i++){
            int c = i > len ? (-1) : (s[i] - 'a'), flg = 0;
            for(int j = c + 1; j < 26; j++) if(ch[p][j]){
                int u = ch[p][j];
                if(Seg.query(rt[u], 1, n, l + i - 1, r)){
                    res = j + 'a', pos = i - 1; break;
                }
            }
            if(ch[p][c]) p = ch[p][c]; else break;
        }
        if(!res) return (void) puts("-1");
        for(int i = 1; i <= pos; i++) putchar(s[i]);
        putchar(res), putchar('\n');
    }
}van;
int main(){
    scanf("%s", s + 1); n = strlen(s + 1);
    for(int i = 1; i <= n; i++) van.ins(s[i] - 'a', i); 
    van.Prework(); int Q;  read(Q);
    for(int i = 1, l, r; i <= Q; i++)
        read(l), read(r), scanf("%s", s + 1), van.solve(s, l, r);
    return 0;
}



猜你喜欢

转载自www.cnblogs.com/mangoyang/p/9643649.html