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