2020CCPC威海站/gym102798 G-Caesar Cipher
题意
给定一个长度为(n)的数组(a),有(q)次询问,每次询问为以下两种之一:
- (1~l~r),将(a)中(lle i le r)的数(a_i)变为((a_i+1)~ ext{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_icdot 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;
}