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 ...
随机推荐
- C++ 中 Concept-Model 概念模型
此文档参考自:https://gracicot.github.io/conceptmodel/2017/09/13/concept-model-part1.html ,觉得很有趣,就翻译过来了 一.C ...
- 解决 pip 安装时的 SSL/TLS 问题
在使用pip安装Python软件包时,有时会遇到与 SSL/TLS 相关的问题.一种常见情况是在使用VPN时出现以下错误信息 ValueError: check_hostname requires s ...
- ContextCapture中的模型航拍方法和技巧
在进行实景建模之前,获取被拍摄物体的照片是很重要的一项工作,因为如果没有按照规则拍摄或者拍摄相片质量不佳,将会直接影响我们后期建模,甚至无法建模. 我们建议使用ContextCapture进行建模,则 ...
- ABP-VNext 用户权限管理系统实战06---实体的创建标准及迁移
在apb-vnext的实体的创建中可以确实字段的长度.说明.对应的表.表中给字段加的索引 以项目中的订单表为例,如下: [Comment("订单主表")] [Table(" ...
- 用 C 语言开发一门编程语言 — Q-表达式
目录 文章目录 目录 前文列表 Q-表达式 读取并存储输入 实现 Q-Expression 语法解析器 读取 Q-Expression 实现 Q-Expression 的函数 Head & T ...
- Pytorch:以单通道(灰度图)加载图片
以单通道(灰度图)加载图片 如果我们想以单通道加载图片,设置加载数据集时的transform参数如下即可: from torchvision import datasets, transforms t ...
- Android 13 - Media框架(31)- ACodec(七)
关注公众号免费阅读全文,进入音视频开发技术分享群! 之前的章节中我们解了 input buffer 是如何传递给 OMX 的,以及Output buffer 是如何分配并且注册给 OMX 的.这一节我 ...
- QGIS开发笔记(三):Windows安装版二次开发环境搭建(下):将QGis融入QtDemo,添加QGis并加载tif遥感图的Demo
前言 使用QGis的目的是进行二次开发,或者说是融入我们的应用(无人车.无人船.无人机),本片描述搭建QGis二次基础开发环境,由于实在是太长了,进行了分篇: 上半部分:主要是安装好后,使用QtC ...
- Keil_MDK中无法打开map文件的解决办法
如果在MDK中打开map文件 我们在STM32的开发过程中,经常会查看.map文件 .map文件是MDK在编译过程中生成的一个包含镜像文件信息的重要文件,在程序编译后自动生成,比方这里我的工程下自动将 ...
- ReplayKit2采用端口转发数据时不能终止的问题
一.现象描述 测试发现在进行USB连接数据投屏中,如果点击屏幕红条进行结束ReplayKit2投屏或者通知栏点击停止录制按钮,大概率出现已经停止录屏,但是通知栏中的录屏按钮还在继续录制的问题 这个现象 ...