字符串
Posted 2016gdgzoi509
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串相关的知识,希望对你有一定的参考价值。
题目
Description
Input
Output
题解
显然用是AC自动机来解决
先说一下没人写的正解
二进制分组, 建\\(O(lgm)\\)个AC自动机。 定义AC自动机的size为这个AC自动机中的字符串个数。 当两个AC自动机size相等时合并这两个AC自动机。时间复杂度\\(O(mlgm)\\)
下面是比较好想, 也比较常规的做法。
题目中说强制在线, 但是却没有给字符串加密。 于是我们不一定要真的在线做。 我们可以用输入中出现的所有字符串建一个AC自动机, 虽然这样会把询问串也包含在内但对结果没有影响。
每次查询还是正常的在AC自动机上走。但由于是动态修改, 我们无法像正常的AC自动机一样预处理, 于是我们需要维护fail树。
把所有fail边拿出来建建一颗树。 然后问题转化成了: 修改一个点的权值, 询问一个点到根路径的权值和。 然后随便用数据结构维护就好了。
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int N = 1000010, M = 2000010;
int ed[N];
struct AC
static const int SIZE = 1000010;
int nxt[SIZE][26], fail[SIZE];
LL val[SIZE];
int root;
int sz;
AC()
void init()
sz = 0;
root = newnode();
int newnode()
memset(nxt[sz], 0, sizeof(nxt[sz]));
fail[sz] = 0;
val[sz] = 0;
return sz++;
void insert(char * str, int len, int id)
int u = root;
for (int i = 0; i < len; i++)
int c = str[i] - 'a';
if (!nxt[u][c])
nxt[u][c] = newnode();
u = nxt[u][c];
ed[id] = u;
void getFail()
queue <int> q;
for (int i = 0; i < 26; i++)
if (nxt[root][i])
fail[nxt[root][i]] = root;
q.push(nxt[root][i]);
else nxt[root][i] = root;
while (!q.empty())
int x = q.front(); q.pop();
for (int i = 0; i < 26; i++)
if (nxt[x][i])
fail[nxt[x][i]] = nxt[fail[x]][i];
q.push(nxt[x][i]);
else nxt[x][i] = nxt[fail[x]][i];
ac;
struct edge
int from, to;
edge()
edge(int _1, int _2) : from(_1), to(_2)
edges[M];
int head[N], nxt[M], tot;
inline void init()
memset(head, -1, sizeof(head));
tot = 0;
inline void add_edge(int x, int y)
edges[tot] = edge(x, y);
nxt[tot] = head[x];
head[x] = tot++;
edges[tot] = edge(y, x);
nxt[tot] = head[y];
head[y] = tot++;
int dfn[N], idf[N], siz[N], dfs_clock;
void dfs(int x, int fa)
dfn[x] = ++dfs_clock;
idf[dfn[x]] = x;
siz[x] = 1;
for (int i = head[x]; ~i; i = nxt[i])
edge & e = edges[i];
if (e.to != fa)
dfs(e.to, x);
siz[x] += siz[e.to];
struct Calc
LL val[N];
void upd(int x, int v)
for (int i = x; i <= dfs_clock; i += (i & -i))
val[i] += v;
LL qry(int x)
LL Ans = 0;
for (int i = x; i > 0; i -= (i & -i))
Ans += val[i];
return Ans;
Calc;
int m;
int opt[N];
char str[N];
int L[N], R[N];
int main()
scanf("%d", &m);
ac.init();
for (int i = 1; i <= m; i++)
scanf("%d", &opt[i]);
L[i] = R[i-1] + 1;
scanf("%s", str + L[i]);
R[i] = L[i] + strlen(str + L[i]) - 1;
ac.insert(str + L[i], R[i] - L[i] + 1, i);
ac.getFail();
init();
for (int i = 1; i < ac.sz; i++)
add_edge(ac.fail[i], i);
dfs(0, -1);
int mask = 0;
for (int i = 1; i <= m; i++)
opt[i] ^= mask;
if (opt[i] == 1)
int x = ed[i];
int l = dfn[x], r = dfn[x] + siz[x] - 1;
Calc.upd(l, 1);
Calc.upd(r + 1, -1);
else if (opt[i] == 2)
int x = ed[i];
int l = dfn[x], r = dfn[x] + siz[x] - 1;
Calc.upd(l, -1);
Calc.upd(r + 1, 1);
else
LL Ans = 0;
int u = ac.root;
for (int j = L[i]; j <= R[i]; j++)
u = ac.nxt[u][str[j] - 'a'];
Ans += Calc.qry(dfn[u]);
mask ^= abs(Ans);
printf("%lld\\n", Ans);
return 0;
以上是关于字符串的主要内容,如果未能解决你的问题,请参考以下文章