2020CCPC威海站/gym102798 G-Caesar Cipher 线段树维护区间hash值
2020CCPC威海站/gym102798 G-Caesar Cipher
题意
给定一个长度为\(n\)的数组\(a\),有\(q\)次询问,每次询问为以下两种之一:
- \(1~l~r\),将\(a\)中\(l\le i \le r\)的数\(a_i\)变为\((a_i+1)~\text{mod}~65536\)。
- \(2~x~y~L\),若区间\([x,x+L-1]\)和区间\([y,y+L-1]\)完全相等,输出"yes",否则输出"no"。
分析
找到一个质数\(b\),线段树维护这样一个数组\(a_1 \cdot b^1,a_2 \cdot b^2,\dots,a_n \cdot b^n\)的区间和,那么区间\([l,r]\)的\(hash\)值即为\(\frac {\sum_{i=l}^{r}a_i\cdot b^i}{b^l}\),同时维护区间\(a_i\)的最大值,对于区间加操作若当前区间的最大值大于等于\(65535\),就继续暴力递归到叶子结点去将大于等于\(65535\)的点修改一下,若区间的最大值小于\(65535\),就区间加上\(\sum_{i=l}^{r} b^i\),并打上标记,这个区间\(b\)的幂次和是可以预处理的,对于每个\(a_i\)最多约有\(\frac{q}{65535}\)次暴力修改的操作,所以总时间复杂度为\(O(\frac{n^2}{65535}logn)\)。
Code
#include <bits/stdc++.h>
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
using namespace std;
typedef long long ll;
const ll mod=1000173169;
const ll base=85531;
const int N=5e5+10;
ll h[N],pre[N];
int n,q;
ll a[N];
ll mx[N<<2],sum[N<<2],tag[N<<2];
ll inv[N];
void bd(int l,int r,int p){
tag[p]=0;
if(l==r){
mx[p]=a[l];
sum[p]=a[l]*h[l]%mod;
return;
}
int mid=l+r>>1;
bd(lson);bd(rson);
mx[p]=max(mx[p<<1],mx[p<<1|1]);
sum[p]=(sum[p<<1]+sum[p<<1|1])%mod;
}
void pd(int l,int r,int p,int k){
mx[p]+=k;
sum[p]=(sum[p]+(pre[r]-pre[l-1]+mod)%mod*k%mod)%mod;
tag[p]+=k;
}
void up(int dl,int dr,int l,int r,int p){
if(l==dl&&r==dr){
if(mx[p]+1<65536){
mx[p]++;
sum[p]=(sum[p]+pre[r]-pre[l-1]+mod)%mod;
tag[p]++;
return;
}else if(l==r){
mx[p]=(mx[p]+1)%65536;
sum[p]=mx[p]*h[l]%mod;
return;
}
}
int mid=l+r>>1;
if(tag[p]) pd(lson,tag[p]),pd(rson,tag[p]);tag[p]=0;
if(dr<=mid) up(dl,dr,lson);
else if(dl>mid) up(dl,dr,rson);
else up(dl,mid,lson),up(mid+1,dr,rson);
mx[p]=max(mx[p<<1],mx[p<<1|1]);
sum[p]=(sum[p<<1]+sum[p<<1|1])%mod;
}
ll qy(int dl,int dr,int l,int r,int p){
if(dl>dr) return 0;
if(l==dl&&r==dr) return sum[p];
int mid=l+r>>1;
if(tag[p]) pd(lson,tag[p]),pd(rson,tag[p]);tag[p]=0;
if(dr<=mid) return qy(dl,dr,lson);
else if(dl>mid) return qy(dl,dr,rson);
else return (qy(dl,mid,lson)+qy(mid+1,dr,rson))%mod;
}
ll ksm(ll a,ll b){
ll ret=1;
while(b){
if(b&1) ret=ret*a%mod;
b>>=1;
a=a*a%mod;
}
return ret;
}
int main()
{
h[0]=1;
pre[0]=1;
for(int i=1;i<N;i++){
h[i]=h[i-1]*base%mod;
pre[i]=(pre[i-1]+h[i])%mod;
inv[i]=ksm(h[i],mod-2);
}
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
bd(1,n,1);
int op,l,r,x,y,L;
while(q--){
scanf("%d",&op);
if(op==1){
scanf("%d%d",&l,&r);
up(l,r,1,n,1);
}else if(op==2){
scanf("%d%d%d",&x,&y,&L);
ll s1=qy(x,x+L-1,1,n,1)*inv[x]%mod;
ll s2=qy(y,y+L-1,1,n,1)*inv[y]%mod;
if(s1==s2) puts("yes");
else puts("no");
}
}
return 0;
}