[Luogu4715]「英语」Z 语言
description
你有一个长度为\(n\)的串\(A\)和一个长度为\(m\)的串\(B\),字符集大小\(2^{31}\),且同一个串中没有相同的元素。
定义\(B\)串与\(A_{i...i+m-1}\)匹配(\(1\le i \le n-m+1\)),当且仅当\(B\)串对应的排列与\(A_{i...i+m-1}\)对应的排列完全相同。
一个串对应的排列就是把串的每个元素的值替换成它在这个串中从小到大的\(Rank\)。由于不存在相同的元素,所以这样子一定会得到一个排列。
现在要动态修改\(B\)串每个位置的元素,并询问每次修改后\(B\)串在\(A\)串中的出现次数。
\(n,m,q\le10^5\)
sol
由于\(A\)串是固定的,我们可以先求出\(A\)串中每个长为\(m\)的子串的\(hash\)值,然后只要动态维护出\(B\)串的\(hash\)值,丢到一个\(map\)里面去找就行了。
但是这个\(hash\)值的计算方法需要只与相对大小有关而与具体数值无关。
我们可以对串维护一棵平衡树,平衡树的键值是串中的数值,并在树上的每个位置维护节点在原串中的下标。
这样两个串匹配就当且仅当他们构出来的平衡树的先序遍历得到的下标序列完全相同。
于是就只需要对这个下标维护一个\(hash\)值即可。
对于\(A_{i...i-m+1},i>1\)的这些子串,下标并不是从\(1\)开始编号,但是可以看作是每个下标都加上了一个固定的常数,那么最终得出来的\(hash\)也就加上了一个可计算得到的常数,减去即可。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
#define ull unsigned long long
const int N = 2e5+5;
const ull base = 20020415;
int n,m,q,a[N],b[N];ull pw[N],delta;
map<ull,int>M;
struct Splay{
int fa[N],ch[2][N],sz[N],val[N],pos[N],root,tot;ull hsh[N];
bool son(int x){return x==ch[1][fa[x]];}
void pushup(int x){
sz[x]=sz[ch[0][x]]+1+sz[ch[1][x]];
hsh[x]=hsh[ch[0][x]]*pw[sz[ch[1][x]]+1]+pos[x]*pw[sz[ch[1][x]]]+hsh[ch[1][x]];
}
void rotate(int x){
int y=fa[x],z=fa[y],c=son(x);
ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y;
fa[x]=z;if (z) ch[son(y)][z]=x;
ch[c^1][x]=y;fa[y]=x;pushup(y);
}
void splay(int x,int goal){
for (int y=fa[x];y!=goal;rotate(x),y=fa[x])
if (fa[y]!=goal) son(x)^son(y)?rotate(x):rotate(y);
pushup(x);if (!goal) root=x;
}
void insert(int v,int p){
if (!root){
root=++tot;val[tot]=v,pos[tot]=p;
pushup(root);return;
}
int x=root;
while (1)
if (v<val[x])
if (!ch[0][x]){
ch[0][x]=++tot;val[tot]=v,pos[tot]=p,fa[tot]=x;
splay(tot,0);return;
}else x=ch[0][x];
else
if (!ch[1][x]){
ch[1][x]=++tot;val[tot]=v,pos[tot]=p,fa[tot]=x;
splay(tot,0);return;
}else x=ch[1][x];
}
int suf(){
int x=ch[1][root];
while (ch[0][x]) x=ch[0][x];
splay(x,root);return x;
}
void erase(int v){
int x=root;
while (1)
if (v<val[x]) x=ch[0][x];
else if (v>val[x]) x=ch[1][x];
else break;
splay(x,0);
if (!ch[1][x]) {fa[root=ch[0][x]]=0;return;}
int y=suf();fa[ch[0][x]]=y;ch[0][y]=ch[0][x];fa[root=y]=0;
}
}A,B;
int main(){
n=gi();m=gi();q=gi();pw[0]=1;
for (int i=1;i<N;++i) pw[i]=pw[i-1]*base;
for (int i=0;i<m;++i) delta+=pw[i];
for (int i=1;i<=n;++i) a[i]=gi();
for (int i=1;i<=m;++i) b[i]=gi();
for (int i=1;i<=m;++i) A.insert(a[i],i);++M[A.hsh[A.root]];
for (int i=m+1;i<=n;++i){
A.erase(a[i-m]);A.insert(a[i],i);
++M[A.hsh[A.root]-delta*(i-m)];
}
for (int i=1;i<=m;++i) B.insert(b[i],i);
while (q--){
int p=gi();B.erase(b[p]);
b[p]=gi();B.insert(b[p],p);
printf("%d\n",M[B.hsh[B.root]]);
}
return 0;
}
[Luogu4715]「英语」Z 语言的更多相关文章
- P4715 「英语」Z 语言
题解: 平衡树维护hash值 为了支持加入删除操作 x*base^y 其中y为他是第k大 同一般的维护方法,我们不用对每个节点维护他的hash值 而是只用记录他的x值(他的位置) 然后通过updata ...
- 「HNOI2004」「LuoguP2292」L语言(AC自动机
题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...
- Python文字转换语音,让你的文字会「说话」,抠脚大汉秒变撒娇萌妹
作者 | pk 哥 来源公众号 | Python知识圈(ID:PythonCircle) APP 也有文字转换为语音的功能,虽然听起来很别扭,但是基本能解决长辈们看不清文字或者眼睛疲劳,通过文字转换为 ...
- 【LOJ】#3046. 「ZJOI2019」语言
LOJ#3046. 「ZJOI2019」语言 先orz zsy吧 有一个\(n\log^3n\)的做法是把树链剖分后,形成logn个区间,这些区间两两搭配可以获得一个矩形,求矩形面积并 然后就是对于一 ...
- 「ZJOI2019」语言 解题报告
「ZJOI2019」语言 3个\(\log\)做法比较简单,但是写起来还是有点麻烦的. 大概就是树剖把链划分为\(\log\)段,然后任意两段可以组成一个矩形,就是个矩形面积并,听说卡卡就过去了. 好 ...
- 正则表达式从入门到放弃「Java」
正则表达式能做什么? 正则表达式可以用来搜索.编辑或处理文本. 「都懂它可以处理文本,可到底是怎么回事?」 正则表达式的定义 百度百科:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特 ...
- 「MoreThanJava」当大学选择了计算机之后应该知道的
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 面试都在问的「微服务」「RPC」「服务治理」「下一代微服务」一文带你彻底搞懂!
❝ 文章每周持续更新,各位的「三连」是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) ❞ 单体式应用程序 与微服务相对的另一个概念是传统的「单体式应用程 ...
- 「MoreThanJava」计算机系统概述
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
随机推荐
- 【平台中间件】Nginx安装配置,实现版本更新不影响服务访问
为什么要做负载均衡? 当你网站是一个企业站.个人博客的时候,或者访问量比较小的时候,一台服务器完全应付的了,那就完全没必要做负载均衡.但是,如果你的网站是平台级别,用户达到十万百万级别了,一台服务器明 ...
- Java接受键盘输入
import java.util.Scanner;//方法1 import java.io.BufferedReader;//方法2 import java.io.IOException;//方法3 ...
- ubuntu下python安装pandas和numpy等依赖库版本不兼容的问题RuntimeWarning: numpy.dtype size changed
习惯了linux下用pip install numpy及pip install pandas命令了.折腾了好久了. 上来先在python3中pip3 install numpy装了numpy,然后再p ...
- 初识 JVM
发展历史 1996年,SUN JDK 1.0 Classic VM 发布,纯解释运行,使用外挂进行JIT 1997年 JDK1.1 发布.包含了:AWT.内部类.JDBC.RMI.反射 1998年 J ...
- 初识HTML和CSS2
上节作业问题: 1.css重用 <style> 如果整个页面的宽度 > 900px时: { .c{ 共有 } .c1{ 独有 } } .c2{ 独有 } </style> ...
- CSS3:边框属性
前言 学习这些CSS属性并不是要自己要设计多好看的样式,而是看到网上的代码能看得懂. 效果 本章将围绕如下效果进行解释: border border-width: 边框宽度. border-style ...
- VisualBrush
VisualBrush是一种比较特殊的笔刷,它的功能仍然是用来给元素填充图案,但它的内容却可以是各种控件(换言之:它可以使用各种控件来给元素填充图案). 你可以将它理解为一个普通的容器,但在它内部的所 ...
- 设计模式--迭代器模式C++实现
迭代器模式C++实现 1定义 他提供一种方法访问一个容器对象中的各个元素,而不暴漏该对象内部细节 注:迭代器是为容器服务的.迭代器模式提供了遍历容器的方便性,容器只管理增减元素就好,需要遍历时交给迭代 ...
- UVA-1619 Feel Good (单调队列)
题目大意:给一个非负整数序列,求出一个使得区间和乘以区间最小值最大的区间. 题目分析:单调队列.维护两个数组,l[i]表示以a[i]为最小值的左半区间的最左边端点,r[i]表示以a[i]为最小值的右半 ...
- JavaScript--跨域
跨域 什么是跨域? 跨域请求就是不同域的网站之间的文件数据之间的传送 ,由于浏览器的同源策略机制(基于安全,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性)Ajax直接请求普通 ...