解题思路:
1.和普通线段树维护哈希不同的是,这里要求原数组对一个数模mod,观察发现区间一次只加1,线段树记录区间最大值,在查询时如果区间的最大值大于等于mod,重建这部分线段树。
2.其他部分和普通的线段树维护哈希就一样了,建议写双哈希,以免被卡。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=5e5+10,P=131,mod1=1e9+7,mod2=1e9+9,mod=65536;
ll n,m;
ll p1[N],p2[N],sum1[N],sum2[N];
ll b[N];
void init(){ // 预处理
p1[0]=1,p2[0]=1;
sum1[0]=1,sum2[0]=1;
for(int i=1;i<N;i++){
p1[i]=p1[i-1]*P%mod1;
p2[i]=p2[i-1]*P%mod2;
sum1[i]=sum1[i-1]+p1[i]%mod1;
sum2[i]=sum2[i-1]+p2[i]%mod2;
}
}
struct PW{
ll hehs1,hehs2,maxn,lazy;
int l,r;
}a[N*4];
void pushdown(int id){ // 更新子节点
a[id<<1].lazy+=a[id].lazy,a[id<<1|1].lazy+=a[id].lazy;
a[id<<1].maxn+=a[id].lazy,a[id<<1|1].maxn+=a[id].lazy;
a[id<<1].hehs1=(a[id<<1].hehs1+(a[id].lazy*sum1[a[id<<1].r-a[id<<1].l]%mod1))%mod1;
a[id<<1].hehs2=(a[id<<1].hehs2+(a[id].lazy*sum2[a[id<<1].r-a[id<<1].l]%mod2))%mod2;
a[id<<1|1].hehs1=(a[id<<1|1].hehs1+(a[id].lazy*sum1[a[id<<1|1].r-a[id<<1|1].l])%mod1)%mod1;
a[id<<1|1].hehs2=(a[id<<1|1].hehs2+(a[id].lazy*sum2[a[id<<1|1].r-a[id<<1|1].l])%mod2)%mod2;
a[id].lazy=0;
}
void pushup(PW &s1,PW &s2,PW &s3){ // 更新父节点
s3.l=s1.l,s3.r=s2.r;
s3.maxn=max(s1.maxn,s2.maxn);
s3.lazy=0;
s3.hehs1=((s1.hehs1*p1[s2.r-s2.l+1]%mod1)+s2.hehs1)%mod1;
s3.hehs2=((s1.hehs2*p2[s2.r-s2.l+1]%mod2)+s2.hehs2)%mod2;
}
void pushup(int id){
pushup(a[id<<1],a[id<<1|1],a[id]);
}
void build(int id,int l,int r){
a[id].l=l,a[id].r=r;
if(l==r){
a[id].hehs1=b[l];
a[id].hehs2=b[l];
a[id].maxn=b[l];
a[id].lazy=0;
return ;
}
else{
int mid=l+r>>1;
build(id<<1,l,mid),build(id<<1|1,mid+1,r);
pushup(id);
}
}
void modify(int id,int l,int r){ // 区间修改
if(a[id].l>=l&&a[id].r<=r){
a[id].lazy++,a[id].maxn++;
a[id].hehs1=a[id].hehs1+sum1[a[id].r-a[id].l]%mod1;
a[id].hehs2=a[id].hehs2+sum2[a[id].r-a[id].l]%mod2;
return ;
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(r<=mid){
modify(id<<1,l,r);
}
else if(l>mid){
modify(id<<1|1,l,r);
}
else{
modify(id<<1,l,r);
modify(id<<1|1,l,r);
}
pushup(id);
}
}
void update(int id){ // 重建线段树
if(a[id].l==a[id].r){ // 递归到叶
b[a[id].l]=a[id].maxn%mod; // 最好用 maxn 值. has1,hesh2 模了模数可能出错
a[id].lazy=0,a[id].maxn=b[a[id].l];
a[id].hehs1=b[a[id].l];
a[id].hehs2=b[a[id].l];
return ;
}
else{
pushdown(id);
update(id<<1),update(id<<1|1);
pushup(id);
}
}
PW query(int id,int l,int r){
if(a[id].l>=l&&a[id].r<=r){
if(a[id].maxn<mod){ // 需要重建
return a[id];
}
else{
update(id);
return a[id];
}
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(r<=mid){
return query(id<<1,l,r);
}
else if(l>mid){
return query(id<<1|1,l,r);
}
else{
PW s1=query(id<<1,l,r);
PW s2=query(id<<1|1,l,r);
PW s3;
pushup(s1,s2,s3);
return s3;
}
}
}
int main(){
guo312;
init();
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>b[i];
}
build(1,1,n);
ll op,l,r,d;
while(m--){
cin>>op;
if(op==1){
cin>>l>>r;
modify(1,l,r);
}
else{
cin>>l>>r>>d;
PW s1=query(1,l,l+d-1);
PW s2=query(1,r,r+d-1);
if(s1.hehs1==s2.hehs1&&s1.hehs2==s2.hehs2) cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
}
return 0;
}