这题感觉不是很难,但是既然放在 \(\texttt{EDU}\) 的 \(\texttt{G}\) 题,那么还是写写题解吧。

\(\texttt{Solution}\)

首先看到 "子串",那么想到 \(\texttt{ACAM}\) 和 \(\texttt{SAM}\)。本篇题解就使用 \(\texttt{ACAM}\)。

然后我们先对于最开始给定的 \(n\) 个串建立一个 \(\texttt{ACAM}\)。

然后考虑对于每一个串在 \(\texttt{ACAM}\) 上对应的位置赋上这个串的值。

查询其实就是在 \(\texttt{fail}\) 树上查询一些节点到根的最大值。

这个其实就是要求在 \(\texttt{fail}\) 树上单点修改,求链上最大值。这个东西树剖很好维护。

然后注意以下一个细节:一个串可能出现多次。这个 \(\texttt{multiset}\) 维护一下最大值就好了

\(\texttt{Code}\)

#include<bits/stdc++.h>
using namespace std;
#define L(i, j, k) for(int i = (j), i##E = (k); i <= i##E; i++)
#define R(i, j, k) for(int i = (j), i##E = (k); i >= i##E; i--)
#define ll long long
#define db double
#define mp make_pair
const int N = 3e5 + 7;
const int M = N * 4;
const int inf = 1e9;
int n, m, endid[N], VAL[N];
int ch[N][26], fa[N], tot = 1;
multiset<int> st[N];
int insert(char *s, int n) {
int now = 1;
L(i, 0, n - 1) {
if(!ch[now][s[i] - 'a']) ch[now][s[i] - 'a'] = ++tot;
now = ch[now][s[i] - 'a'];
}
return now;
}
void bfs() {
queue<int> q;
L(i, 0, 25) if(ch[1][i]) fa[ch[1][i]] = 1, q.push(ch[1][i]); else ch[1][i] = 1;
while(!q.empty()) {
int u = q.front();
q.pop();
L(i, 0, 25) {
int v = ch[u][i];
if(!v) ch[u][i] = ch[fa[u]][i];
else fa[v] = ch[fa[u]][i], q.push(v);
}
}
}
int head[N], edge_id;
struct node { int to, next; } e[N << 1];
void add_edge(int u, int v) {
++edge_id, e[edge_id].next = head[u], e[edge_id].to = v, head[u] = edge_id;
}
int siz[N], maxto[N], dep[N], uid[N], idtot, heavy[N];
void dfs1(int x) {
siz[x] = 1;
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
fa[v] = x, dep[v] = dep[x] + 1, dfs1(v), siz[x] += siz[v];
if(siz[v] > siz[heavy[x]]) heavy[x] = v;
}
}
void dfs2(int x) {
uid[x] = ++idtot;
if(heavy[x]) maxto[heavy[x]] = maxto[x], dfs2(heavy[x]);
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
if(v == heavy[x]) continue;
maxto[v] = v, dfs2(v);
}
}
int maxn[M];
void build(int x, int l, int r) {
maxn[x] = -1;
if(l == r) return;
int mid = (l + r) / 2;
build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
}
void add(int id, int L, int R, int wz, int val) {
// if(id == 1) cout << wz << " is : " << val << endl;
if(L == R) return maxn[id] = val, void();
int mid = (L + R) / 2;
if(wz <= mid) add(id << 1, L, mid, wz, val);
else add(id << 1 | 1, mid + 1, R, wz, val);
maxn[id] = max(maxn[id << 1], maxn[id << 1 | 1]);
}
int query(int id, int L, int R, int l, int r) {
if(l <= L && R <= r) return maxn[id];
int mid = (L + R) / 2, res = -1;
if(l <= mid) res = max(res, query(id << 1, L, mid, l, r));
if(r > mid) res = max(res, query(id << 1 | 1, mid + 1, R, l, r));
// if(id == 1) cout << l << " to " << r << "'s max = " << res << endl;
return res;
}
int get(int x) {
int res = -1;
while(x) res = max(res, query(1, 1, tot, uid[maxto[x]], uid[x])), x = fa[maxto[x]];
return res;
}
char s[N];
int main() {
scanf("%d%d", &n, &m);
L(i, 1, n) scanf("%s", s), endid[i] = insert(s, strlen(s));
bfs();
L(i, 2, tot) add_edge(fa[i], i);
dfs1(1), maxto[1] = 1, dfs2(1);
build(1, 1, tot);
L(i, 1, n) add(1, 1, tot, uid[endid[i]], 0), st[endid[i]].insert(0);
while(m--) {
int opt, x, val;
scanf("%d", &opt);
if(opt == 1) {
scanf("%d%d", &x, &val);
int now = endid[x];
st[now].erase(st[now].lower_bound(VAL[x]));
st[now].insert(val), VAL[x] = val;
add(1, 1, tot, uid[now], *st[now].rbegin());
}
else {
int maxn = -1, now = 1;
scanf("%s", s);
L(i, 0, strlen(s) - 1) now = ch[now][s[i] - 'a'], maxn = max(maxn, get(now));
printf("%d\n", maxn);
}
}
return 0;
}

题解 CF1437G Death DBMS的更多相关文章

  1. CF1437G Death DBMS

    题面传送门. 题意简述:给出 \(n\) 个字符串 \(s_i\),每个 \(s_i\) 初始权值为 \(0\).\(q\) 次操作:修改 \(s_i\) 的权值:查询给出字符串 \(q\) 能匹配的 ...

  2. ACAM 题乱做

    之前做了不少 ACAM,不过没怎么整理起来,还是有点可惜的. 打 * 的是推荐一做的题目. I. *CF1437G Death DBMS 见 我的题解. II. *CF1202E You Are Gi ...

  3. Educational Codeforces Round 97 (Rated for Div. 2)

    补了一场Edu round. A : Marketing Scheme 水题 #include <cstdio> #include <algorithm> typedef lo ...

  4. Death to Binary? (模拟)题解

    思路: 除去前导0,注意两个1不能相邻(11->100),注意 0 *** 或者*** 0或者0 0情况 用string的reverse()很舒服 代码: #include<cstdio& ...

  5. HDU 5860 Death Sequence(死亡序列)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  6. 字符串(AC自动机):HDU 5129 Yong Zheng's Death

    Yong Zheng's Death Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/O ...

  7. HDU 5860 Death Sequence(递推)

    HDU 5860 Death Sequence(递推) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 Description You ...

  8. Vulnhub靶场题解

    Vulnhub简介 Vulnhub是一个提供各种漏洞环境的靶场平台,供安全爱好者学习渗透使用,大部分环境是做好的虚拟机镜像文件,镜像预先设计了多种漏洞,需要使用VMware或者VirtualBox运行 ...

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

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

随机推荐

  1. linux 内核 同步原理

    中断分为同步中断和异步中断. 同步中断是由CPU控制单元产生的,"同步"是指只有在一条指令执行完毕后,CPU才会发出中断,比如系统调用 异步中断是由其他硬件设备依照CPU时钟信号产 ...

  2. 《.NET 5.0 背锅案》第5集-案情大转弯:都是我们的错,让 .NET 5.0 背锅

    第1集:验证 .NET 5.0 正式版 docker 镜像问题 第2集:码中的小窟窿,背后的大坑,发现重要嫌犯 EnyimMemcachedCore 第3集-剧情反转:EnyimMemcachedCo ...

  3. Java的强引用、软引用、弱引用、虚引用

    背景 工程中用到guava的本地缓存.它底层实现和API接口上使用了强引用.软引用.弱引用.所以温故知新下,也夯实下基础. 预备知识 先来看下GC日志每个字段的含义 Young GC示例解释 [GC ...

  4. ceph luminous 新功能之内置dashboard

    前言 ceph luminous版本新增加了很多有意思的功能,这个也是一个长期支持版本,所以这些新功能的特性还是很值得期待的,从底层的存储改造,消息方式的改变,以及一些之前未实现的功能的完成,都让ce ...

  5. git-新建git用户流程-1

    1.输入:https://git-scm.com/ 2.点击try git 4.注册git填写用户名和密码,邮箱,验证邮箱 5.选择免费的版本 6.创建仓库名称 创建成功见截图

  6. kettle练习

    Kettle实现,把数据从CSV文件复制到Excel文件. 首先,创建一个转换,找到核心对象,找到输入里面的CVS文件输入图元,拖拽到工作区域,双击CVS文件输入. 可以修改步骤的名称,点击浏览,选择 ...

  7. Mac OS终端利器 iTem2 配置大全

    转载链接:https://www.cnblogs.com/diyxiaoshitou/p/9017413.html 之前一直使用 Mac OS 自带的终端,用起来虽然有些不太方便,但总体来说还是可以接 ...

  8. 总是说spring难学?来看完这些spring的注解及其解释,真香!

    前言 用过spring的人都知道,spring简单的通过注解就可以完成很多事情,但这些东西是如何实现的呢以及如何应用到我们自己的代码中?接下来,让我们一起开启注解的旅程. 1. @Controller ...

  9. python3处理csv文件

    1. 基础语句 1.1 文件的读取 如果需要读取一行数据如下表1所示,那么需要读取域名下面的数据,便使用如下代码: with open('A.csv','rb') as csvfile: reader ...

  10. ABBYY FineReader 12/14版本功能对比及14产品优势

    FineReader 是一款一体化的 OCR 和PDF编辑转换器,随着版本的更新,功能的增加,FineReader 14的推出继续为用户在处理文档时提高业务生产力,该版本包含若干新特性和功能增强,包括 ...