线段树+哈希【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. POJ 1014 / HDU 1059 Dividing 多重背包+二进制分解

    Problem Description Marsha and Bill own a collection of marbles. They want to split the collection a ...

  2. 【BZOJ2287】消失之物 [分治][DP]

    消失之物 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ftiasch 有 N 个物品, ...

  3. SQL语句中的单引号处理以及模糊查询

    为了防止程序SQL语句错误以及SQL注入,单引号必须经过处理.有2种办法: 1.使用参数,比如SELECT * FROM yourTable WHERE name = @name; 在C#中使用Sql ...

  4. MSSQL数据库 "无法删除数据库 "***",因为该数据库当前正在使用" 解决方案

    --1 创建数据库 create database AAA --2 使用数据库 use AAA --3 在AAA数据库下创建table create table BBB ( bId ,) primar ...

  5. 如何免费上传4G以上大文件至百度云网盘

    百度云网盘的容量高达2048G,因而如今使用百度云网盘的用户也越来越多, 但是百度云中如果要上传超过4G的大文件,必须要升级VIP才行,但这需要收费.那么,超过4G以上的大文件我们该怎样上传到百度云呢 ...

  6. charles https抓包

    1. 配置 Charles 根证书 首先打开 Charles: Charles 启动界面 主界面 然后如下图操作:   之后会弹出钥匙串,如果不弹出,请自行打开钥匙串,如下图: 钥匙串 系统默认是不信 ...

  7. 64_g5

    golang-github-kr-text-devel-0-0.11.git6807e77.f..> 11-Feb-2017 07:48 14250 golang-github-kr-text- ...

  8. git学习笔记二-branch分支

    1.刚创建好的空仓库的分支是空的,即使是master分支也是不存在的.master分支是不能通过git branch 来创建的,只有在完成第一次提交才会自动创建,有git自动完成master分子的创建 ...

  9. 实现atoi函数

    atoi函数最关键的地方是想好测试用例: 输入为空字符串,输出为0; 输入字符串大小超过INT_MAX输出INT_MAX; 输入字符串大小小于INT_MIN输出INT_MIN; 输入字符串中含有不规则 ...

  10. c语言中数组,指针数组,数组指针,二维数组指针

    1.数组和指针 ] = {,,,,};// 定义数组 // 1. 指针和数组的关系 int * pa = array; pa = array; // p[0] == *(p+0) == array[0 ...