BZOJ 2434 阿狸的打字机

题意 : 回答第x个模式串在第y个模式串中出现了几次。数据范围\(\sum_n,\sum_m,q\leq10^5\)

显然可以离线,对于相同y的询问集中处理,暴跳fail的时候开个桶丢进去,最后把有用的提出来。

但是还是太慢了。

考虑问题本质:对于一组询问\(x,y\)实际上是在问属于串\(y\)的节点有多少\(fail\)边指向\(x\)

可以注意到每个点有且仅有一个\(fail\) 于是从这个点的\(fail\)向这个点连边

然后就是dfs序BIT维护

但是插入串串太慢了

我们考虑在原来的trie树上走,进入一个点时+1,离开时-1,避免了重复插入删除。

这样对于不同的\(x\)也能继续进行回答。

因为没特判没有关于落在这个点上的串的询问导致RE了一上午

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
const int N = 1e5 + 7;
int pcnt = 1, endp[N], ecnt, last[N];
struct trie {int son[26], vis[26], fail, fa, end, sum;} t[N];
struct graph {int next, to;} e[N*5];
inline void add(int u, int v) {e[++ecnt].next = last[u], e[ecnt].to = v, last[u] = ecnt;}
int xcnt;
inline void ins(char *ss) {
  int lens = strlen(ss), p = 1;
  for (int i = 0; i < lens; i++) {
    if (ss[i] == 'B') p = t[p].fa;
    else if (ss[i] == 'P') endp[++xcnt] = p, t[p].sum++, t[p].end = xcnt;
    else {
      if (!t[p].son[ss[i] - 'a']) t[p].son[ss[i] - 'a'] = ++pcnt, t[pcnt].fa = p;
      p = t[p].son[ss[i] - 'a'];
    } 
  }
}
inline void getfail() {
  std :: queue<int> que;
  t[1].fail = 1;
  for (int i = 0; i < 26; i++) if (t[1].son[i]) 
    que.push(t[1].son[i]), t[t[1].son[i]].fail = 1;
  else t[1].son[i] = 1;
  while (!que.empty()) {
    int u = que.front(); que.pop();
    for (int i = 0; i < 26; i++) if (t[u].son[i]) 
      t[t[u].son[i]].fail = t[t[u].fail].son[i], que.push(t[u].son[i]);
    else t[u].son[i] = t[t[u].fail].son[i];
  }
}
int dfn[N], c[N*10], low[N];int cnt;
inline int lbt(int x) {return (x & (-x));}
inline void modify(int x, int k) {while(x <= cnt) c[x] += k, x += lbt(x);}
inline int getc(int x) {int res = 0;while(x) res += c[x], x -= lbt(x);return res;} 
inline void dfs1(int x) { 
  dfn[x] = ++cnt; 
  for (int i = last[x]; i; i = e[i].next) dfs1(e[i].to); 
  low[x] = cnt;
} 
struct ques {int x, y, id, ans;} q[N];
bool operator < (ques a, ques b) {return a.y < b.y;}
int lastans[N], sum[N];
char ss[N]; int n, ql[N], qr[N];
inline void dfs2(int x) {
  modify(dfn[x], 1); 
  if (t[x].end && ql[t[x].end]) 
   for (int i = ql[t[x].end]; i <= qr[t[x].end]; i++) 
    q[i].ans = getc(low[endp[q[i].x]]) - getc(dfn[endp[q[i].x]] - 1);
  for (int i = 0; i < 26; i++) if (t[x].vis[i]) dfs2(t[x].vis[i]);
  modify(dfn[x], -1);
}
int main() {
  scanf("%s", ss), ins(ss), scanf ("%d", &n); 
  for (int i = 1; i <= pcnt; i++)for (int j = 0; j < 26; j++) t[i].vis[j] = t[i].son[j];
  for (int i = 1; i <= n; i++) scanf ("%d%d", &q[i].x, &q[i].y), q[i].id = i;
  std :: sort (&q[1], &q[n + 1]);getfail();
  for (int i = 2; i <= pcnt; i++) add(t[i].fail, i); dfs1(1);
  for (int i = 1, opt = 1; i <= n; i = opt) {
    ql[q[i].y] = i; while(q[opt].y == q[i].y) opt++; qr[q[i].y] = opt - 1;
  } dfs2(1);
  for (int i = 1; i <= n; i++) lastans[q[i].id] = q[i].ans;
  for (int i = 1; i <= n; i++) printf("%d\n", lastans[i]);
return 0;
}
posted @ 2019-10-08 21:38  ComeIntoCalm  阅读(63)  评论(0编辑  收藏  举报