来一份线性时间的题解。

考虑先解决前缀限制,显然可以直接把字符串和询问全部搬到 Trie 树上,问题就变成了查询一个子树内满足后缀限制的字符串数量。

接着考虑 Trie 树合并,具体地,把后缀限制以及字符串挂在单词节点上,接着遍历整个 Trie 每到一个节点就把这个节点的儿子的所有 Trie 树合并并将这个节点挂着的字符串插入,随后回答询问,当然这个 Trie 树要从末位插入解决后缀限制。

由于每进行一次合并操作就会减少一个 Trie 上的节点又因为节点数量是 \(O(\sum |S_i| + |P_i| + |Q_i|)\) 的所以复杂度就是线性的。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e6 + 114;
struct Big_Trie {
char c;
int ch[4];//A G U C
} tr1[maxn];
int answer[maxn];
int tot1, rt1;
struct Small_Trie {
char c;
int ch[4];//A G U C
int cnt;//单词节点数量
int sz;
} tr2[maxn];
int tot2;
int rt2[maxn];
int merge(int a, int b) {
if (a == 0 || b == 0)
return a + b; tr2[a].ch[0] = merge(tr2[a].ch[0], tr2[b].ch[0]);
tr2[a].ch[1] = merge(tr2[a].ch[1], tr2[b].ch[1]);
tr2[a].ch[2] = merge(tr2[a].ch[2], tr2[b].ch[2]);
tr2[a].ch[3] = merge(tr2[a].ch[3], tr2[b].ch[3]);
tr2[a].cnt += tr2[b].cnt;
tr2[a].sz = tr2[tr2[a].ch[0]].sz + tr2[tr2[a].ch[1]].sz + tr2[tr2[a].ch[2]].sz + tr2[tr2[a].ch[3]].sz +
tr2[a].cnt;
return a;
}
void insert(int &cur, string &s) {
if (cur == 0)
cur = ++tot2; if (s.size() == 0) {
tr2[cur].cnt++;
tr2[cur].sz = tr2[tr2[cur].ch[0]].sz + tr2[tr2[cur].ch[1]].sz + tr2[tr2[cur].ch[2]].sz +
tr2[tr2[cur].ch[3]].sz + tr2[cur].cnt;
return ;
} else if (s[s.size() - 1] == 'A')
s.pop_back(), insert(tr2[cur].ch[0], s);
else if (s[s.size() - 1] == 'G')
s.pop_back(), insert(tr2[cur].ch[1], s);
else if (s[s.size() - 1] == 'U')
s.pop_back(), insert(tr2[cur].ch[2], s);
else if (s[s.size() - 1] == 'C')
s.pop_back(), insert(tr2[cur].ch[3], s); tr2[cur].sz = tr2[tr2[cur].ch[0]].sz + tr2[tr2[cur].ch[1]].sz + tr2[tr2[cur].ch[2]].sz +
tr2[tr2[cur].ch[3]].sz + tr2[cur].cnt;
}
int query(int cur, string &s) {
if (cur == 0)
return 0;
else if (s.size() == 0) {
return tr2[cur].sz;
} else if (s[s.size() - 1] == 'A') {
s.pop_back();
return query(tr2[cur].ch[0], s);
} else if (s[s.size() - 1] == 'G') {
s.pop_back();
return query(tr2[cur].ch[1], s);
} else if (s[s.size() - 1] == 'U') {
s.pop_back();
return query(tr2[cur].ch[2], s);
} else if (s[s.size() - 1] == 'C') {
s.pop_back();
return query(tr2[cur].ch[3], s);
} return 0;
}
vector<string> str[maxn];
void Ins_str(int &cur, string &s, string &Suf) {
if (cur == 0)
cur = ++tot1; if (s.size() == 0) {
str[cur].push_back(Suf);
return ;
} else if (s[s.size() - 1] == 'A')
s.pop_back(), Ins_str(tr1[cur].ch[0], s, Suf);
else if (s[s.size() - 1] == 'G')
s.pop_back(), Ins_str(tr1[cur].ch[1], s, Suf);
else if (s[s.size() - 1] == 'U')
s.pop_back(), Ins_str(tr1[cur].ch[2], s, Suf);
else if (s[s.size() - 1] == 'C')
s.pop_back(), Ins_str(tr1[cur].ch[3], s, Suf);
}
vector< pair<string, int>> Q[maxn];
void Ins_ask(int &cur, string &s, string &Suf, int id) {
if (cur == 0)
cur = ++tot1; if (s.size() == 0) {
Q[cur].push_back(make_pair(Suf, id));
return ;
} else if (s[s.size() - 1] == 'A')
s.pop_back(), Ins_ask(tr1[cur].ch[0], s, Suf, id);
else if (s[s.size() - 1] == 'G')
s.pop_back(), Ins_ask(tr1[cur].ch[1], s, Suf, id);
else if (s[s.size() - 1] == 'U')
s.pop_back(), Ins_ask(tr1[cur].ch[2], s, Suf, id);
else if (s[s.size() - 1] == 'C')
s.pop_back(), Ins_ask(tr1[cur].ch[3], s, Suf, id);
}
void dfs(int cur) {
if (cur == 0)
return ; dfs(tr1[cur].ch[0]), rt2[cur] = merge(rt2[cur], rt2[tr1[cur].ch[0]]);
dfs(tr1[cur].ch[1]), rt2[cur] = merge(rt2[cur], rt2[tr1[cur].ch[1]]);
dfs(tr1[cur].ch[2]), rt2[cur] = merge(rt2[cur], rt2[tr1[cur].ch[2]]);
dfs(tr1[cur].ch[3]), rt2[cur] = merge(rt2[cur], rt2[tr1[cur].ch[3]]); for (string now : str[cur]) {
insert(rt2[cur], now);
} for (pair<string, int> now : Q[cur]) {
answer[now.second] = query(rt2[cur], now.first);
}
}
int n, m;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m; for (int i = 1; i <= n; i++) {
string s, rs;
cin >> s; for (int i = s.size() - 1; i >= 0; i--)
rs.push_back(s[i]); Ins_str(rt1, rs, s);
} for (int i = 1; i <= m; i++) {
string p, q, rp;
cin >> p >> q; for (int i = p.size() - 1; i >= 0; i--)
rp.push_back(p[i]); Ins_ask(rt1, rp, q, i);
} dfs(rt1); for (int i = 1; i <= m; i++)
cout << answer[i] << '\n';
}

P9196 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. SATA与PCI-E速度对比

    SATA SATA接口已经发展到了第三代,理论上的最大速度达到600MB/s.平时大家见到的SATA SSD使用的都是SATA三代,实际测试速度在550MB/s左右,这比普通的机械硬盘的速度100MB ...

  2. kettle使用4-使用Pan.bat执行转换、Kitchen.bat执行作业

    一.直接在spoon中执行作业 使用bat文件执行速度比执行在spoon.bat中执行慢很多,如果少数几个任务,可以直接在spoon中执行. 1.新建作业 2.在通用中,新建START 任务执行的时间 ...

  3. C语言:使用链式栈检测txt文件中的括号匹配

    便捷目录 前言 本程序最终会完成的任务 栈的理解 代码运行过程的解释 说明 ==代码思想 (重要部分)== 全局变量和结构体代码 进栈:创建链表空间函数 出栈:删除链表空间函数 释放申请的链式栈空间 ...

  4. C语言:将字符逆反排列再输出的问题

    代码: #include<stdio.h> #define N 10 int main() { /*输入字符串,str[10],将里面的字符逆反排列,再输出.*/ char ch[N]; ...

  5. 用tkinter编写一个简单的登录注册界面

    代码: from tkinter import * window = Tk() window.geometry('400x300+500+150') window.title('xxx系统') Can ...

  6. Vue cli构建项目

    一.创建项目 vue create hello-world 你会被提示选取一个 preset.你可以选默认的包含了基本的 Babel + ESLint 设置的 preset,也可以选"手动选 ...

  7. Vue cli之创建组件

    一般在开发中,我们会人为把组件分2个目录存放,一个代表的页面组件,另一个代表页面一部分的子组件. src/ |- views/ |- Home.vue |- components/ |- App.vu ...

  8. Opencv笔记(12)傅里叶变换

    在之前了解的OpenCV为我们实现的图像变换,这些本质上是从图像到输出图像的映射,即输入仍是一幅图像.本章的傅里叶变换,输出数组的值在含义上和原图像的强度值大不相同,是输入图像的频域表示. cv::d ...

  9. itest(爱测试) 开源接口测试,敏捷测试管理平台10.1.4发布

    一:itest work 简介 itest work 开源敏捷测试管理,包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock,还有压测 ,又有丰富的统计分析,8合1工作站.可按 ...

  10. 字符型 ASCLL编码 转义字符

    字符(character) char 2字节   每一个字符的背后.都有一个数字做代表(对照,参照的表) 字符赋值 char cl = 'a';通过''单引号描述为字符赋值 整数赋值 char c2 ...