P9196 题解
来一份线性时间的题解。
考虑先解决前缀限制,显然可以直接把字符串和询问全部搬到 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 题解的更多相关文章
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
- JSOI2016R3 瞎BB题解
题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...
随机推荐
- SATA与PCI-E速度对比
SATA SATA接口已经发展到了第三代,理论上的最大速度达到600MB/s.平时大家见到的SATA SSD使用的都是SATA三代,实际测试速度在550MB/s左右,这比普通的机械硬盘的速度100MB ...
- kettle使用4-使用Pan.bat执行转换、Kitchen.bat执行作业
一.直接在spoon中执行作业 使用bat文件执行速度比执行在spoon.bat中执行慢很多,如果少数几个任务,可以直接在spoon中执行. 1.新建作业 2.在通用中,新建START 任务执行的时间 ...
- C语言:使用链式栈检测txt文件中的括号匹配
便捷目录 前言 本程序最终会完成的任务 栈的理解 代码运行过程的解释 说明 ==代码思想 (重要部分)== 全局变量和结构体代码 进栈:创建链表空间函数 出栈:删除链表空间函数 释放申请的链式栈空间 ...
- C语言:将字符逆反排列再输出的问题
代码: #include<stdio.h> #define N 10 int main() { /*输入字符串,str[10],将里面的字符逆反排列,再输出.*/ char ch[N]; ...
- 用tkinter编写一个简单的登录注册界面
代码: from tkinter import * window = Tk() window.geometry('400x300+500+150') window.title('xxx系统') Can ...
- Vue cli构建项目
一.创建项目 vue create hello-world 你会被提示选取一个 preset.你可以选默认的包含了基本的 Babel + ESLint 设置的 preset,也可以选"手动选 ...
- Vue cli之创建组件
一般在开发中,我们会人为把组件分2个目录存放,一个代表的页面组件,另一个代表页面一部分的子组件. src/ |- views/ |- Home.vue |- components/ |- App.vu ...
- Opencv笔记(12)傅里叶变换
在之前了解的OpenCV为我们实现的图像变换,这些本质上是从图像到输出图像的映射,即输入仍是一幅图像.本章的傅里叶变换,输出数组的值在含义上和原图像的强度值大不相同,是输入图像的频域表示. cv::d ...
- itest(爱测试) 开源接口测试,敏捷测试管理平台10.1.4发布
一:itest work 简介 itest work 开源敏捷测试管理,包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock,还有压测 ,又有丰富的统计分析,8合1工作站.可按 ...
- 字符型 ASCLL编码 转义字符
字符(character) char 2字节 每一个字符的背后.都有一个数字做代表(对照,参照的表) 字符赋值 char cl = 'a';通过''单引号描述为字符赋值 整数赋值 char c2 ...