CF1037H Security
Posted cjc030205
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1037H Security相关的知识,希望对你有一定的参考价值。
题源:https://codeforces.com/problemset/problem/1037/H
sol:
考虑怎么判断一个节点是否在([L,R])内,
如果一个串当前在sam上匹配到第(j)位,那么如果串在([L,R])内,那么他的(endpos)就是(x+j),
并且如果以(L)位起始那么终点在(L+i-1)上,所以线段树合并维护点的(endpos)集合即可。
对母串建sam,然后把(endpos)插到对应的点的线段树上去。
对于一个询问,明显是改变的位越往后且越小越好,倒序枚举位置,贪心做这个选择。
注意把(0)的(pos)初始化为(1)
复杂度(vert Svert nlog n)
#include<cstdio>
#include<cstring>
#define debug printf("GG
")
const int N = 1e5+7;
const int S = 26;
typedef long long LL;
#define R register
struct Trie {
int son[S], len, end, fail;
} t[N*2];
int tot = 1, last = 1;
struct segt {
int cnt;
struct Node {
int lc, rc, sum;
} t[N*8];
void pushup(int u) {
t[u].sum = t[t[u].lc].sum + t[t[u].rc].sum;
}
void Modify(int &u, int l, int r, int x) {
if (!u) u = ++cnt;
t[u].sum++;
if (l == r) {
return;
}
int MID = (l + r) >> 1;
if (x <= MID) Modify(t[u].lc, l, MID, x);
else Modify(t[u].rc, MID + 1, r, x);
pushup(u);
}
int Merge(int u, int v) {
if (!u) return v;
if (!v) return u;
int a = ++cnt;
t[a].sum = t[u].sum + t[v].sum;
t[a].lc = Merge(t[u].lc, t[v].lc);
t[a].rc = Merge(t[u].rc, t[v].rc);
return a;
}
int query(int u, int l, int r, int sl, int sr) {
if (!u) return 0;
if (sl == l && sr == r) return t[u].sum;
int MID = (l + r) >> 1;
if (sr <= MID) return query(t[u].lc, l, MID, sl, sr);
else if (sl > MID) return query(t[u].rc, MID + 1, r, sl, sr);
else return query(t[u].lc, l, MID, sl, MID) + query(t[u].rc, MID + 1, r, MID + 1, sr);
}
}T;
inline void ins(int c) {
int np = ++tot, p = last;
t[np].len = t[p].len + 1, last = np;
for ( ; p && (!t[p].son[c]); p = t[p].fail) t[p].son[c] = np;
if (!p) {
t[np].fail = 1;
} else {
int q = t[p].son[c];
if (t[q].len == t[p].len + 1) {
t[np].fail = q;
} else {
int cur = ++tot;
t[cur].fail = t[q].fail, t[cur].len = t[p].len + 1;
for (R int o = 0; o < S; o++)
t[cur].son[o] = t[q].son[o];
while (p && (t[p].son[c] == q)) {
t[p].son[c] = cur;
p = t[p].fail;
}
t[q].fail = t[np].fail = cur;
}
}
}
LL c[N*2], rk[N*2];
int rt[N*4], pos[N*2];
char ss[N], tmp[N];
int main() {
T.cnt = 0;
int len;
scanf("%s", ss + 1);
len = strlen(ss + 1);
for (R int i = 1; i <= len; i++) {
ins(ss[i] - 'a');
T.Modify(rt[last], 1, len, i);
}
/* for (R int i = 1; i <= tot; i++) c[t[i].len]++;
for (R int i = 1; i <= tot; i++) c[i] += c[i - 1];
for (R int i = 1; i <= tot; i++) rk[c[t[i].len]--] = i;
for (R int i = tot; i > 1; i--) rt[t[rk[i]].fail] = T.Merge(rt[t[rk[i]].fail], rt[rk[i]]);*/
for (R int i = tot; i > 1; i--) rt[t[i].fail] = T.Merge(rt[t[i].fail], rt[i]);
int Q;
scanf("%d", &Q);
while (Q--) {
int L, sr;
scanf("%d%d", &L, &sr);
scanf("%s", tmp + 1);
int lens = strlen(tmp + 1);int limit = lens;
//!!!!!!!!
pos[0] = 1;
//!!!!!
for (R int i = 1, p = 1; i <= lens; i++) {
if (t[p].son[tmp[i] - 'a']) {
p = t[p].son[tmp[i] - 'a'], pos[i] = p;
} else {
limit = i - 1; break;
}
}
//debug;
int flag = 0;
for (R int i = limit; i >= 0; i--) {
if (flag) break;
for (R int j = (i == lens ? 0 : tmp[i + 1] - 'a' + 1); j < S; j++) {
//if (i == 1) debug;
if (L + i > sr) continue;
if (T.query(rt[t[pos[i]].son[j]], 1, len, L + i, sr)) {
for (R int k = 1; k <= i; k++)
putchar(tmp[k]);
putchar(j + 'a');
printf("
");
flag = 1;
break;
}
}
}
if (!flag) printf("-1
");
}
}
以上是关于CF1037H Security的主要内容,如果未能解决你的问题,请参考以下文章
CF1037H Security 后缀自动机 + right集合线段树合并 + 贪心