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 S\vert n\log n\)

#include<cstdio>
#include<cstring>
#define debug printf("GG\n")
const int N = 2e5+7;
const int S = 26;
typedef long long LL;
#define R register
struct Trie {
  int son[S], len, end, fail;
} t[N*3];
int tot = 1, last = 1;
struct segt {
  int cnt;
  struct Node {
    int lc, rc, sum;
  } t[N*33];
  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;
    }
  }
}
int c[N*2], rk[N*2];
int rt[N*4], pos[N*2];
char ss[N], tmp[N*2];
int main() {
  T.cnt = 0;
  int len;
  scanf("%s", ss + 1);
  len = strlen(ss + 1);
  //len *= 2;
  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 ? tmp[i + 1] - 'a' + 1: 0); 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("\n");
          flag = 1;
          break;
        }
      }
    }
    if (!flag) printf("-1\n");
  }
return 0;
}
posted @ 2019-10-13 20:13  ComeIntoCalm  阅读(...)  评论(...编辑  收藏