题意:
给定长度为n的数字串
有两种操作:
(1,L,R,d)将[L,R]所有数字修改为d
(2,L,R,d)问d是否是[L,R]的循环节
数据范围:n<=1e5,操作数<=1e5
解法:
判断d是否是[L,R]的循环节可以转化为判断[L,R-d]与[L+d,R]是否相等(挺容易验证的),可以用hash在O(1)时间内判断
但是这题存在区间覆盖操作,也就是存在修改,考虑如何维护hash值
选用的hash法为BKDRhash法
BKDRhash法是将整个串设为一个p进制数,那么第x位a(x)的hash值就是a(x)pk,因为数字很大,结果需要模上一个质数
预处理px,那么用线段树维护a(x)px,树上左右节点的合并就是左右节点值相加
覆盖操作:
假设覆盖[L,R]为val,即将树上[L,R]节点的值修改为val*(pl+pl+1+…+pr),可以预处理底数前缀和O(1)计算
判断是否相等的时候:
假设[L,R-d]的hash值为aa,[L+d,R]的hash值为bb,将aa乘上pd(p进制下右移d位)后两个区间的底数才对应
之后判断aa和bb是否相等即可
坑点:
要特判区间长度等于d的情况,因为这时候[L,R-d]与[L+d,R]的左端点会大于右端点,导致线段树查询越界
容易失误的地方:
每个hash值的计算点都要取模,只要有一个地方漏了就会WA
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
const int mod=1e9+7;
const int p=1331;
int laz[N<<2];
int a[N<<2];
int base[N];
int base_[N];//base前缀和
int n,m,k;
int ppow(int a,int b,int mod){
int ans=1%mod;a%=mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void pushup(int node){
a[node]=a[node*2]+a[node*2+1];
}
void pushdown(int l,int r,int node){
if(laz[node]!=-1){
int mid=(l+r)/2;
laz[node*2]=laz[node];
laz[node*2+1]=laz[node];
a[node*2]=((base_[mid]-base_[l-1])*laz[node]%mod+mod)%mod;
a[node*2+1]=((base_[r]-base_[mid])*laz[node]%mod+mod)%mod;
laz[node]=-1;
}
}
void build(int l,int r,int node){
laz[node]=-1;
if(l==r){
char c;cin>>c;
a[node]=base[l]*(c-'0')%mod;
return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pushup(node);
}
void update(int st,int ed,int val,int l,int r,int node){
if(st<=l&&ed>=r){
laz[node]=val;
a[node]=((base_[r]-base_[l-1])*val%mod+mod)%mod;
return ;
}
pushdown(l,r,node);
int mid=(l+r)/2;
if(st<=mid)update(st,ed,val,l,mid,node*2);
if(ed>mid)update(st,ed,val,mid+1,r,node*2+1);
pushup(node);
}
int ask(int st,int ed,int l,int r,int node){
if(st<=l&&ed>=r){
return a[node];
}
pushdown(l,r,node);
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
if(ed>mid)ans+=ask(st,ed,mid+1,r,node*2+1);
ans%=mod;
pushup(node);
return ans;
}
signed main(){
base[0]=1;
for(int i=1;i<N;i++){
base[i]=base[i-1]*p%mod;
}
base_[0]=1;
for(int i=1;i<N;i++){
base_[i]=(base_[i-1]+base[i])%mod;
}
cin>>n>>m>>k;
build(1,n,1);
for(int i=1;i<=m+k;i++){
int op,l,r,d;cin>>op>>l>>r>>d;
if(op==1){//区间覆盖
update(l,r,d,1,n,1);
}else{//查询
if(r-l+1==d){
puts("YES");
continue;
}
int aa=ask(l,r-d,1,n,1);
aa=aa*ppow(p,d,mod)%mod;
int bb=ask(l+d,r,1,n,1);
puts(aa==bb?"YES":"NO");
}
}
return 0;
}