标签:图片 long return abs rom ems 复杂 出现 输入
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;
}
标签:图片 long return abs rom ems 复杂 出现 输入
原文地址:https://www.cnblogs.com/2016gdgzoi509/p/11313066.html