CF1037H Security

https://www.luogu.com.cn/problem/CF1037H

发现其实如果SAM每个节点表示最后一个endpos,那么子树的并其实就是这个节点对应的endpos集合

只需用线段树合并维护即可

跑到一个节点上,你要看这个子串的出现位置,只需看endpos集合在对应区间有没有出现过即可
代码实现非常简单

code:

#include<bits/stdc++.h>
#define N 200050
using namespace std;
#define ls ch[rt][0]
#define rs ch[rt][1]
int ch[N << 5][2], sz, root[N << 5];
void add(int &rt, int l, int r, int x) {
    if(!rt) rt = ++ sz;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(x <= mid) add(ls, l, mid, x);
    else add(rs, mid + 1, r, x);
}
int query(int rt, int l, int r, int L, int R) {
    if(!rt) return 0;
    if(L <= l && r <= R) return 1;
    int mid = (l + r) >> 1, ret = 0;
    if(L <= mid) ret |= query(ls, l, mid, L, R);
    if(R > mid) ret |= query(rs, mid + 1, r, L, R);
    return ret;
}
int merge(int x, int y) {
    if(!x || !y) return x + y;
    int rt = ++ sz;
    ls = merge(ch[x][0], ch[y][0]);
    rs = merge(ch[x][1], ch[y][1]);
    return rt;
}
struct A {
    int ch[27], len, fa;
} a[N << 2];
int lst = 1, tot = 1, n, q;
void insert(int c) {
    int p = lst, np = ++ tot; lst = np;
    a[np].len = a[p].len + 1;
    
    add(root[np], 1, n, a[np].len);
    
    while(p && !a[p].ch[c]) a[p].ch[c] = np, p = a[p].fa;
    if(!p) a[np].fa = 1;
    else {
        int q = a[p].ch[c];
        if(a[q].len == a[p].len + 1) a[np].fa = q;
        else {
            int clone = ++ tot; a[clone] = a[q];
            a[clone].len = a[p].len + 1;
            while(p && a[p].ch[c] == q) a[p].ch[c] = clone, p = a[p].fa;
            a[q].fa = a[np].fa = clone;
        }
    }
}
vector<int> g[N];
void dfs(int u) {
    for(int i = 0; i < g[u].size(); i ++) {
        int v = g[u][i];
        dfs(v); root[u] = merge(root[u], root[v]);
    }
}
char st[N];
int ans[N];
int main() {
    scanf("%s", st + 1); n = strlen(st + 1);
    for(int i = 1; i <= n; i ++) insert(st[i] - 'a');
    for(int i = 2; i <= tot; i ++) g[a[i].fa].push_back(i);
    dfs(1);
    
    scanf("%d", &q);
    while(q --) {
        int l, r, p = 1;
        scanf("%d%d %s", &l, &r, st + 1);
        int m = strlen(st + 1), j = m + 1;
        for(int i = 1; i <= m + 1; i ++) {
            ans[i] = -1;
            for(int c = max(0, st[i] - 'a' + 1); c < 26; c ++) {
                int v = a[p].ch[c];
                if(v && query(root[v], 1, n, l + i - 1, r)) {
                    ans[i] = c;
                    break;
                }
            }
            p = a[p].ch[st[i] - 'a'];
            if(!p || !query(root[p], 1, n, l + i - 1, r)) {j = i; break;}
        }
       // for(int i = 1; i <= m + 1; i ++) printf("%d ", ans[i]); printf("\n");
        while(ans[j] == -1 && j) j --;
        if(!j) printf("-1\n");
        else {
            for(int i = 1; i < j; i ++) printf("%c", st[i]);
            printf("%c", char(ans[j] + 'a'));
            printf("\n");
        }
    }
    return 0;
}
posted @ 2021-09-07 21:37  lahlah  阅读(45)  评论(0编辑  收藏  举报