• [COCI2015]Divljak


    \(\text{Analysis}\)

    \(ACAM\) 毕业题:\(\text{[COCI2015]Divljak}\)
    确信
    \(AC\) 自动机加树链剖分加树状数组,加深了对 \(fail\) 数组的理解
    \(AC\) 自动机的工作模式知先用模式串建出 \(Trie\)\(fail\) 数组
    然后加入字符串操作,考虑这个字符串能包含那些模式串,给这些模式串答案加 \(1\)
    模拟文本串在自动机上匹配的过程,有一个不断跳 \(fail\) 指针的过程
    对于 \(fail\) 位置上存在的模式串,答案均要加 \(1\)
    在多个询问中,这是一个极其缓慢的过程
    考虑 \(Trie\) 上所有 \(fail_x\)\(x\) 的边形成一个 \(fail\)
    不断跳 \(fail\) 指针的过程即一个点跳到根的过程
    这样就可以用数据结构处理了
    考虑一个串的加入经过 \(AC\) 自动机上若干个关键点
    这些关键点在 \(fail\) 树中到根的点集的并就是我们要维护的点
    要维护的点答案加且只加 \(1\)
    不难想到只将关键点加 \(1\),询问时找到当前字符串在 \(fail\) 树上的点,将以它为根的子树记录的贡献相加即可
    发现一个插入操作中多个关键点对它们的 \(LCA\) 及以上的点只贡献 \(1\)
    将关键点按 \(dfs\) 序排序后,相邻点的 \(LCA\)\(1\) 即可
    修改和查询均可用树状数组完成

    \(\text{Code}\)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #define RE register
    #define IN inline
    using namespace std;
    
    const int N = 2e6 + 5;
    int n, id[N], size = 1, h[N], tot, Q[N];
    char s[N];
    struct edge{int to, nxt;}e[N];
    IN void add(int x, int y){e[++tot] = edge{y, h[x]}, h[x] = tot;}
    
    struct ACAM{
    	int tr[N][26], fail[N];
    	IN void insert(int x)
    	{
    		int len = strlen(s), u = 1, c;
    		for(RE int i = 0; i < len; i++)
    		{
    			c = s[i] - 'a';
    			if (!tr[u][c]) tr[u][c] = ++size;
    			u = tr[u][c];
    		}
    		id[x] = u;
    	}
    	IN void getfail()
    	{
    		int h = 0, t = 0, now;
    		for(RE int i = 0; i < 26; i++)
    			if (tr[1][i]) Q[++t] = tr[1][i], fail[Q[t]] = 1;
    			else tr[1][i] = 1;
    		while (h < t)
    		{
    			now = Q[++h];
    			for(RE int i = 0; i < 26; i++)
    				if (tr[now][i]) fail[tr[now][i]] = tr[fail[now]][i], Q[++t] = tr[now][i];
    				else tr[now][i] = tr[fail[now]][i];
    		}
    		for(RE int i = 2; i <= size; i++) add(fail[i], i);
    	}
    }AC;
    
    int top[N], siz[N], dfn[N], dfc, son[N], rev[N], fa[N], dep[N];
    void dfs1(int x)
    {
    	siz[x] = 1, dep[x] = dep[fa[x]] + 1;
    	for(RE int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		fa[v] = x, dfs1(v), siz[x] += siz[v];
    		if (siz[son[x]] < siz[v]) son[x] = v;
    	}
    }
    void dfs2(int x, int t)
    {
    	top[x] = t, dfn[x] = ++dfc, rev[dfc] = x;
    	if (son[x]) dfs2(son[x], t);
    	for(RE int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == son[x]) continue;
    		dfs2(v, v);
    	}
    }
    IN int LCA(int x, int y)
    {
    	int fx = top[x], fy = top[y];
    	while (fx ^ fy)
    	{
    		if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
    		x = fa[fx], fx = top[x];
    	}
    	if (dep[x] < dep[y]) return x;
    	return y;
    }
    
    struct BIT{
    	int c[N];
    	IN int lowbit(int x){return x & (-x);}
    	IN void add(int x, int v){if (x > 1) for(; x <= size; x += lowbit(x)) c[x] += v;}
    	IN int Query(int x){int s = 0; for(; x; x -= lowbit(x)) s += c[x]; return s;}
    }T;
    
    IN bool cmp(int x, int y){return dfn[x] < dfn[y];}
    IN void update()
    {
    	int len = strlen(s), u = 1, c, t = 0;
    	for(RE int i = 0; i < len; i++)
    		c = s[i] - 'a', u = AC.tr[u][c], Q[++t] = u, T.add(dfn[u], 1);
    	sort(Q + 1, Q + t + 1, cmp);
    	for(RE int i = 1; i < t; i++) T.add(dfn[LCA(Q[i], Q[i + 1])], -1);
    }
    
    IN void read(int &x)
    {
    	x = 0; char ch = getchar(); int f = 1;
    	for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
    	for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
    	x *= f;
    }
    
    int main()
    {
    	read(n);
    	for(RE int i = 1; i <= n; i++) scanf("%s", s), AC.insert(i);
    	AC.getfail(), dfs1(1), dfs2(1, 1); int q; read(q);
    	for(int op, x; q; --q)
    	{
    		read(op);
    		if (op == 1) scanf("%s", s), update();
    		else read(x), printf("%d\n", T.Query(dfn[id[x]] + siz[id[x]] - 1) - T.Query(dfn[id[x]] - 1));
    	}
    }
    
  • 相关阅读:
    k-匿名算法
    门控循环单元(GRU)与 LSTM 的区别
    计算机视觉之相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
    CMU-Multimodal SDK Version 1.1 (mmsdk)使用方法总结
    机器学习 – 练习题:一段1米长的绳子 随机切两刀 分成三段 求能够组合成一个三角形的概率
    pickle导入变量AttributeError的解决方案
    typing类型注解库
    灰度共生矩阵(Gray-level Co-occurrence Matrix,GLCM),矩阵的特征量
    几何不变矩--Hu矩
    对 GAN 的 value function 的理解
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/16464241.html
Copyright © 2020-2023  润新知