Codeforces 1207 G. Indie Album

解题思路

离线下来用SAM或者AC自动机就是一个单点加子树求和,套个树状数组就好了,因为这个题广义SAM不能存在 \(len[u] = len[fa]\) 的节点,需要特殊处理,所以写一个博客来贴板子,之前用Awd博客上的那个好像不太能处理干净。

code


/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf ((ll) 1e18)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
} const int N = 1600005; vector<int> g[N], d[N], rt;
vector<pair<int, int> > q[N];
string str[N];
char strr[N];
int ans[N], n, m; namespace Bit{
int s[N];
inline void modify(int x, int y){
for(int i = x; i < N; i += i & -i) s[i] += y;
}
inline int query(int l, int r){
int res = 0;
for(int i = l - 1; i; i -= i & -i) res -= s[i];
for(int i = r; i; i -= i & -i) res += s[i];
return res;
}
}
namespace SAM{
vector<int> g[N];
int ch[N][26], dfn[N], len[N], fa[N], sz[N], size = 1, tail = 1, cnt;
inline int newnode(int x){ return len[++size] = x, size; }
inline void ins(int c, int pos){
int p = tail;
if(ch[p][c]){
if(ch[p][c] && len[ch[p][c]] == len[p] + 1){
int np = ch[p][c];
if(pos <= n) d[pos].push_back(np);
return (void) (tail = np);
}
int np = newnode(len[p] + 1), q = ch[p][c];
if(pos <= n) d[pos].push_back(np);
fa[np] = fa[q], fa[q] = np;
for(int i = 0; i < 26; i++) ch[np][i] = ch[q][i];
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = np;
return (void) (tail = np);
}
int np = newnode(len[p] + 1);
if(pos <= n) d[pos].push_back(np);
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) return (void) (fa[np] = 1, tail = np);
int q = ch[p][c];
if(len[q] == len[p] + 1) fa[np] = q;
else{
int nq = newnode(len[p] + 1);
fa[nq] = fa[q], fa[q] = fa[np] = nq;
for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
} tail = np;
}
inline void addedge(){
for(int i = 2; i <= size; i++) g[fa[i]].push_back(i);
}
inline void dfs(int u){
dfn[u] = ++cnt, sz[u] = 1;
for(int i = 0; i < (int) g[u].size(); i++)
dfs(g[u][i]), sz[u] += sz[g[u][i]];
}
}
inline void build(int u){
int tmp = SAM::tail;
for(int i = 0; i < (int) str[u].size(); i++)
SAM::ins(str[u][i] - 'a', u);
for(int i = 0; i < (int) g[u].size(); i++)
build(g[u][i]);
SAM::tail = tmp;
}
inline void solve(int u){
for(int i = 0; i < (int) d[u].size(); i++)
Bit::modify(SAM::dfn[d[u][i]], 1);
for(int i = 0; i < (int) q[u].size(); i++){
int x = q[u][i].first, y = q[u][i].second;
ans[x] = Bit::query(SAM::dfn[y], SAM::dfn[y] + SAM::sz[y] - 1);
}
for(int i = 0; i < (int) g[u].size(); i++)
solve(g[u][i]);
for(int i = 0; i < (int) d[u].size(); i++)
Bit::modify(SAM::dfn[d[u][i]], -1);
}
int main(){
read(n);
for(int i = 1, x, y; i <= n; i++){
read(x);
if(x == 1)
cin >> str[i], rt.push_back(i);
else
read(y), cin >> str[i], g[y].push_back(i);
}
for(int i = 0; i < (int) rt.size(); i++)
build(rt[i]);
read(m);
for(int i = 1, x; i <= m; i++){
read(x), scanf("%s", strr);
int lenth = strlen(strr);
for(int j = 0; j < lenth; j++)
SAM::ins(strr[j] - 'a', n + 1);
q[x].push_back(make_pair(i, SAM::tail));
SAM::tail = 1;
}
SAM::addedge(), SAM::dfs(1);
for(int i = 0; i < (int) rt.size(); i++)
solve(rt[i]);
for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}

Codeforces 1207 G. Indie Album的更多相关文章

  1. CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)

    题意:有N个串,给出的形式是拼接给出,对于第i行:  (1,c)表示字符串i是单个字母c: (2,p,c)表示字符串i=在字符串p后面接上一个字母c. 然后给出M个提问,形式是(i,string).问 ...

  2. CF G. Indie Album AC自动机+fail树+线段树

    这个套路挺有意思的. 把 $trie$ 和 $fail$ 树都建出来,然后一起跑一跑就好了~ #include <queue> #include <cstdio> #inclu ...

  3. CF G. Indie Album 广义后缀自动机+树链剖分+线段树合并

    这里给出一个后缀自动机的做法. 假设每次询问 $t$ 在所有 $s$ 中的出现次数,那么这是非常简单的: 直接对 $s$ 构建后缀自动机,随便维护一下 $endpos$ 大小就可以. 然而,想求 $t ...

  4. [codeforces 549]G. Happy Line

    [codeforces 549]G. Happy Line 试题描述 Do you like summer? Residents of Berland do. They especially love ...

  5. CodeForces 794 G.Replace All

    CodeForces 794 G.Replace All 解题思路 首先如果字符串 \(A, B\) 没有匹配,那么二元组 \((S, T)\) 合法的一个必要条件是存在正整数对 \((x,y)\), ...

  6. codeforces 659 G. Fence Divercity 组合数学 dp

    http://codeforces.com/problemset/problem/659/G 思路: f(i,0/1,0/1) 表示到了第i个,要被切的块开始了没有,结束了没有的状态的方案数 递推看代 ...

  7. Codeforces 803 G. Periodic RMQ Problem

    题目链接:http://codeforces.com/problemset/problem/803/G 大致就是线段树动态开节点. 然后考虑到如果一个点还没有出现过,那么这个点显然未被修改,就将这个点 ...

  8. Codeforces 954 G. Castle Defense

    http://codeforces.com/problemset/problem/954/G 二分答案 检验的时候,从前往后枚举,如果发现某个位置的防御力<二分的值,那么新加的位置肯定是越靠后越 ...

  9. Codeforces 746 G. New Roads

    题目链接:http://codeforces.com/contest/746/problem/G mamaya,不知道YY了一个什么做法就这样过去了啊 2333 首先我显然可以随便构造出一棵树满足他所 ...

随机推荐

  1. 一个禁用mac内置键盘的方法

    一个禁用mac内置键盘的方法 强大的 karabiner, 非常好用. 可以直接在有外接键盘连接的情况下, 禁用掉内置键盘 另外一个方法是启用mac的 鼠标键, 感觉用处不是很大, 修饰健并没有被禁用 ...

  2. C Primer Plus--高级数据结构之二叉树

    目录 二叉搜索树 Binary Search Tree 用C构建二叉树ADT 树结构的定义 C Primer Plus--高级数据结构表示之二叉树 二叉搜索树 Binary Search Tree 二 ...

  3. flume 测试 hive sink

    测试flume,将数据送到hive表中,首先建表. create table order_flume( order_id string, user_id string, eval_set string ...

  4. 第12组 Beta版本演示

    前言 组长博客 组名: To Be Done 组员和贡献比例 短学号 姓名 分工 贡献比例 614 王永福* 前后端实现.发任务.催进度 30% 440 孙承恺 UI设计 15% 529 邱畅杰 文本 ...

  5. nRF52832 串口仅支持偶检验

    通常在使用串口时,我们习惯是不进行奇偶检验(even/odd parity),让应用层的软件自己检验即可.如果非要硬件校验时,以下是关于NRF52832的奇偶检验配置: // 52832 仅支持 ev ...

  6. 【洛谷】P4198 楼房重建(线段树)

    传送门 分析 被线段树按在地上摩擦  先把左边转化成斜率,那么这个题就转化成每次修改一个点的值,输出前缀最大值的个数 看到标签是线段树,所以还是想想线段树的做法吧 既然是线段树,那么就要将区间分成两半 ...

  7. Clion下同时编写多个main函数

    在你的CMakeLists.txt文件下配置,使用add_executable(),前面的一定要不一样 红色部分是描述main的,配置后运行处可以选择:

  8. golang 文件传输小demo(转载)

    转载地址:https://www.cnblogs.com/qq702368956/p/10195497.html 获取文件信息需要用到os. Stat接口,发送文件前开启接收者(服务端),启动客户端先 ...

  9. pdfBox 解析 pdf文件

    Spting boot 项目 1.添加依赖 <dependency> <groupId>org.apache.pdfbox</groupId> <artifa ...

  10. jmeter测试 flask 接口请求

    jmeter测试 flask 接口请求 flask的代码如下: #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flas ...