线段树+哈希【CF580E】Kefa and Watch

Description

\(n\)个数的字符串,\(m + k\)个操作

1 l r k把\(l - r\)赋值为\(k\)

2 l r d询问\(l - r\)是否有长度为\(d\)的循环节

\(n \leq 10^5, m + k \leq 10^5, d \leq 10\)

Input

第一行为三个整数\(n,m,k\)

第二行为一个\(n\)个数的字符串。

接下来\(m+k\)行每行对应一种操作。

Output

对于每一个\(2\)操作,如果存在,输出一行\(YES\),否则输出\(NO\)

线段树维护哈希

写起来爽,调起来更爽

我们首先预处理出\(po\)数组记录\(base^i\)(这个要用来修改及查询的。)

还要预处理出来\(val[i][j]\)代表长度为\(j\)的全部为数字\(i\)的字符串的哈希值。

然后每次区间合并的时候.

\[len=tr[rs].r-tr[rs].l+1 \\
tr[o].va=(tr[ls].va\times po[len]%\ mod +tr[rs].va) %\ mod
\]

这个应该不是很难理解吧。(就类似于你\(hash\)匹配的做法。)

修改时候,我们直接赋值\(tr[o].va=val[k][len]\)即可。

需要注意的有两点:

  1. \(lazy\)标记初值要为\(1\),因为会存在赋值为\(0\)的情况
  2. 查询操作中,当前区间分别在左右两侧的时候\(tr[ls].va \times po[r-mid]\)!!

因此直接码代码就好了

还有一个神仙结论是做题的根据。

如果询问为\((l,r,d)\),则只需要判断\((l+d,r)\)和\((l,r-d)\)即可。

证明的话,我不太会.但是这是正确的。

如果这题卡单\(hash\)的话可以写双\(hash\)。稍作修改即可。不多\(BB\)了.

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#define lo long long
#define base 31
#define mod 20020303
#define R register using namespace std; const int gz=1e5+8; inline void in(R int &x)
{
int f=1;x=0;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s)){x=x*10+s-'0';s=getchar();}
x*=f;
} int n,m,K,po[gz]={1},val[10][gz]; char s[gz]; struct wc
{
int l,r,tg;
lo va;
}tr[gz<<2]; inline void pre()
{
for(R int i=1;i<gz;i++)
po[i]=po[i-1]*base%mod;
for(R int i=0;i<10;i++)
for(R int j=1;j<gz;j++)
val[i][j]=(val[i][j-1]*base%mod+i)%mod;
} #define ls o<<1
#define rs o<<1|1 inline void up(R int o)
{
tr[o].va=(tr[ls].va*po[tr[rs].r-tr[rs].l+1]%mod+tr[rs].va%mod)%mod;
} void build(R int o,R int l,R int r)
{
tr[o].l=l,tr[o].r=r;tr[o].tg=-1;
if(l==r)
{
tr[o].va=s[l]-'0';
return;
}
R int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
up(o);
} inline void down(R int o)
{
if(tr[o].tg==-1)return;
R int k=tr[o].tg;
tr[ls].va=val[k][tr[ls].r-tr[ls].l+1];
tr[rs].va=val[k][tr[rs].r-tr[rs].l+1];
tr[ls].tg=tr[rs].tg=k;
tr[o].tg=-1;
} void change(R int o,R int l,R int r,R int k)
{
if(tr[o].l==l and tr[o].r==r)
{
tr[o].tg=k;
tr[o].va=val[k][tr[o].r-tr[o].l+1];
return ;
}
down(o);
R int mid=(tr[o].l+tr[o].r)>>1;
if(r<=mid)change(ls,l,r,k);
else if(l>mid)change(rs,l,r,k);
else change(ls,l,mid,k),change(rs,mid+1,r,k);
up(o);
} lo query(R int o,R int l,R int r)
{
if(tr[o].l==l and tr[o].r==r)return tr[o].va;
down(o);
R int mid=(tr[o].l+tr[o].r)>>1;
if(r<=mid)return query(ls,l,r);
else if(l>mid) return query(rs,l,r);
else
return ((query(ls,l,mid)%mod)*po[r-mid]%mod+query(rs,mid+1,r)%mod)%mod;//注意这里!!
} int main()
{
pre();
in(n),in(m),in(K);
R int tt=m+K;
scanf("%s",s+1);
build(1,1,n);
for(R int opt,l,r,k;tt;tt--)
{
in(opt),in(l),in(r),in(k);
switch(opt)
{
case 1:change(1,l,r,k);break;
case 2:
{
if(r-l+1==k)
{
puts("YES");
continue;
}
puts(query(1,l,r-k)==query(1,l+k,r) ? "YES":"NO");
break;
}
}
}
}

线段树+哈希【CF580E】Kefa and Watch的更多相关文章

  1. 【线段树哈希】「Balkan OI 2016」Haker

    1A海星 题目大意 给你一个长度为 $n$ ,由小写字母构成的字符串 $S$ 和 $Q$ 个操作,每个操作是以下 3 种之一: 1 x y k :询问当前字符串从位置 $x$ 到 $y$ 的子串与从位 ...

  2. cf580E. Kefa and Watch(线段树维护字符串hash)

    题意 $n$个数的序列,$m + k$种操作 1.$l , r, k$把$l - r$赋值为$k$ 2.$l, r, d$询问$l - r$是否有长度为$d$的循环节 Sol 首先有个神仙结论:若询问 ...

  3. Codeforces Round #321 (Div. 2) E. Kefa and Watch 线段树hash

    E. Kefa and Watch Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/580/prob ...

  4. 51Nod1553 周期串查询 字符串 哈希 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1553.html 题目传送门 - 51Nod1553 题意 有一个串只包含数字字符.串的长度为n,下标 ...

  5. 线段树 + 字符串Hash - Codeforces 580E Kefa and Watch

    Kefa and Watch Problem's Link Mean: 给你一个长度为n的字符串s,有两种操作: 1 L R C : 把s[l,r]全部变为c; 2 L R d : 询问s[l,r]是 ...

  6. [bzoj2124]等差子序列——线段树+字符串哈希

    题目大意 给一个1到N的排列\(A_i\),询问是否存在\(p_i\),\(i>=3\),使得\(A_{p_1}, A_{p_2}, ... ,A_{p_len}\)是一个等差序列. 题解 显然 ...

  7. CF213E Two Permutations 线段树维护哈希值

    当初竟然看成子串了$qwq$,不过老师的$ppt$也错了$qwq$ 由于子序列一定是的排列,所以考虑插入$1$到$m$到$n-m+1$到$n$; 如何判断呢?可以用哈希$qwq$: 我们用线段树维护哈 ...

  8. HDU3973 线段树 + 字符哈希

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3973 , 线段树 + 字符哈希,好题. 又学了一种新的哈希方法,hhhh~ 解法: 想法是用P进制的数 ...

  9. 【URAL 1989】 Subpalindromes(线段树维护哈希)

    Description You have a string and queries of two types: replace i'th character of the string by char ...

随机推荐

  1. PowerDesigner16 状态图

    状态图(Statechart Diagram)主要用于描述一个对象在其生存期间的动态行为,表现为一个对象所经历的状态序列,引起状态转移的事件(Event),以及因状态转移而伴随的动作(Action). ...

  2. js 拖动滑块验证

    备注:拖动滑块时尽量平移,chrome浏览器上没有卡顿情况,但是搜狗极速模式和360极速模式都遇到了卡顿,拖不动情况,应是浏览器内部对事件响应速度导致吧. JS代码: ;(function ($,wi ...

  3. 炒鸡简单的canvas粒子(山东数漫江湖)

    位图的canvas一直不会被svg比下去的原因了. 俗话说,须弥芥子,是大小之说,也有以小见大之说,颗颗粒子,足以构建宏大效果. 这是一篇炒鸡简单的canvas粒子教程,主要是讲如何粒子特效的原理,一 ...

  4. 什么是AMD规范

    AMD规范全称是Asynchronous Module Definition,即异步模块加载机制.从它的规范描述页面看,AMD很短也很简单,但它却完整描述了模块的定义,依赖关系,引用关系以及加载机制. ...

  5. 4.0docker部署

    设置容器的端口映射 -P  :容器暴露的所有端口映射 -p :指定映射容器暴露的端口 Nginx部暑流程 docker run -p 80 --name web -t -i ubuntu /bin/b ...

  6. js中的indexOf

    1.概述 indexOf大小写敏感,其中的O要大写 2.对于字符串而言 indexOf返回字符串第一次出现的位置,若没有出现返回-1 var str = "hello world" ...

  7. linux系统引导流程

    1.固件:硬件和软件结合.加电自检是我们按下电源会检测硬件像cpu.内存.网卡等信息.(从硬件层次检测硬件是否可用) 固件设置实例:设置时间 软件时间和硬件时间: [root@VM_0_12_cent ...

  8. MFC单文档框架分析及执行流程(转)

    原文转自 https://blog.csdn.net/u011619422/article/details/40402705 首先来分析一下MFC单文档类的结构: 它包括如下几个类: CAboutDl ...

  9. 【Python学习】Jupyter解决单个变量输出问题

    使用Jupyter的时候有时候发现,我明明写了好几个变量打印,但是它只显示最后一个.Out只有一个. 但是使用下面的语句.就可以实现多个输出. from IPython.core.interactiv ...

  10. C++学习之路(七):以const,enum,inline替换#define

    这篇博文主要是编程中的一些问题和技巧.如题目所示,这些关键字的作用不再进行描述.直接描述功能和实例代码. 首先,在头文件中对类进行定义,是不会为类分配内存空间的,在这一点上类定义可以和普通变量类型的声 ...