如果没有取模,直接维护线段树哈希,原理跟普通哈希是相同的,就是维护一个哈希数组
本题有取模操作,其实有一个常见的套路就是我们发现取模的次数并不会太多,因此对最大值超过限制的区间直接暴力取模变成0,这样复杂度还是可以过关的
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+10; const int base=131; const int mod=1e9+7; ll f[N]; struct node{ int l,r; ll mx; ll lazy; ll h; ll base; }tr[N<<2]; int a[N]; int n,q; void init(){ int i; f[0]=1; for(i=1;i<=n;i++){ f[i]=f[i-1]*base%mod; } } void pushup(int u){ tr[u].h=(tr[u<<1].h+tr[u<<1|1].h)%mod; tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx); } void build(int u,int l,int r){ if(l==r){ tr[u]={l,r,a[l],0,a[l]*f[l]%mod,f[l]}; } else{ tr[u]={l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); tr[u].base=(tr[u<<1].base+tr[u<<1|1].base)%mod; pushup(u); } } void pushdown(int u){ ll x=tr[u].lazy; tr[u<<1].lazy+=x; tr[u<<1|1].lazy+=x; tr[u<<1].mx+=x; tr[u<<1|1].mx+=x; tr[u<<1].h=(tr[u<<1].h+tr[u<<1].base*x)%mod; tr[u<<1|1].h=(tr[u<<1|1].h+tr[u<<1|1].base*x)%mod; tr[u].lazy=0; } void modify(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].h=(tr[u].h+tr[u].base)%mod; tr[u].mx++; tr[u].lazy++; return ; } if(tr[u].lazy) pushdown(u); int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r); if(r>mid) modify(u<<1|1,l,r); pushup(u); } void modify_mod(int u){ if(tr[u].mx<65536) return ; if(tr[u].l==tr[u].r){ tr[u].mx=0; tr[u].h=0; return ; } if(tr[u].lazy) pushdown(u); int mid=tr[u].l+tr[u].r>>1; modify_mod(u<<1); modify_mod(u<<1|1); pushup(u); } ll query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r){ return tr[u].h; } if(tr[u].lazy) pushdown(u); int mid=tr[u].l+tr[u].r>>1; ll ans=0; if(l<=mid) ans=query(u<<1,l,r); if(r>mid) ans=(ans+query(u<<1|1,l,r))%mod; return ans; } int main(){ ios::sync_with_stdio(false); cin>>n>>q; int i; init(); for(i=1;i<=n;i++){ cin>>a[i]; } build(1,1,n); while(q--){ int opt; cin>>opt; if(opt==1){ int l,r; cin>>l>>r; modify(1,l,r); modify_mod(1); } else{ int l,r,len; cin>>l>>r>>len; if(l>r) swap(l,r); if(query(1,l,l+len-1)*f[r-l]%mod==query(1,r,r+len-1)) cout<<"yes"<<endl; else{ cout<<"no"<<endl; } } } }