gym102798 Caesar Cipher (2020 China Collegiate Programming Contest, Weihai Site) 线段树
题意
有一个一个长度为n的数组a和两种操作(1代表对区间\([l,r]\)加1,2代表询问区间\([x,x+L-1]\)和区间\([y,y+L-1]\)是否相同),其中操作1对65536取模。
思路
容易想到可以用哈希判断是否相等。然后题目中的数组是对65536取模的,就会想到hash的模数取65536,即用unsigned short
自然溢出取模,但是这个模数被出题人卡掉了。
另外,做字符串哈希时,哈希的模数一般会选用大指数。因为当base和mod互质时,这个hash函数在\([0,mod)\)上每个值概率相等,此时单次比较的错误率为\(\frac1{mod}\)
对于65536取模的情况,与codeforces438D相同,除了区间和外再加一个区间最大值,对于大于等于65536的区间暴力修改。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll base=1e8+7;
const int maxn=5e5+5;
struct Tree{
ll max,sum,tag;
}tree[maxn*4];
ll a[maxn],p[maxn],pre[maxn];
int n,q;
ll M(ll val){
return val>=mod?val-mod:val<0?val+mod:val;
}
void push_up(int i)
{
tree[i].max=max(tree[i<<1].max,tree[i<<1|1].max);
tree[i].sum=M(tree[i<<1].sum+tree[i<<1|1].sum);
}
void push_down(int i,int L,int R)
{
if(tree[i].tag)
{
tree[i<<1].max+=tree[i].tag;
tree[i<<1|1].max+=tree[i].tag;
int mid=L+R>>1;
if(L!=mid)
tree[i<<1].tag+=tree[i].tag;
if(mid+1!=R)
tree[i<<1|1].tag+=tree[i].tag;
tree[i<<1].sum=M(tree[i<<1].sum+M(pre[mid]-pre[L-1])*tree[i].tag%mod);
tree[i<<1|1].sum=M(tree[i<<1|1].sum+M(pre[R]-pre[mid])*tree[i].tag%mod);
tree[i].tag=0;
}
}
void build(int i,int l,int r)
{
if(l==r)
{
tree[i].max=a[l];
tree[i].sum=a[l]*p[l]%mod;
tree[i].tag=0;
return;
}
int mid=l+r>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
push_up(i);
}
void add(int i,int l,int r,int L,int R)
{
push_down(i,L,R);
if(l==L && r==R)
{
if(l==r)
{
tree[i].max++;
if(tree[i].max==65536)tree[i].max=0;
tree[i].sum=tree[i].max*p[l]%mod;
return;
}
else if(tree[i].max<65535)
{
tree[i].max++;
tree[i].tag++;
tree[i].sum=M(tree[i].sum+M(pre[R]-pre[L-1]));
return;
}
}
int mid=L+R>>1;
if(r<=mid)
add(i<<1,l,r,L,mid);
else if(l>mid)
add(i<<1|1,l,r,mid+1,R);
else
{
add(i<<1,l,mid,L,mid);
add(i<<1|1,mid+1,r,mid+1,R);
}
push_up(i);
}
ll cal(int i,int l,int r,int L,int R)
{
push_down(i,L,R);
int mid=L+R>>1;
if(l==L && r==R)return tree[i].sum;
if(r<=mid)
return cal(i<<1,l,r,L,mid);
else if(l>mid)
return cal(i<<1|1,l,r,mid+1,R);
else
return M(cal(i<<1,l,mid,L,mid)+cal(i<<1|1,mid+1,r,mid+1,R));
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>a[i];
p[0]=1;
pre[0]=1;
for(int i=1;i<=n;i++)
{
p[i]=p[i-1]*base%mod;
pre[i]=M(pre[i-1]+p[i]);
}
build(1,1,n);
int op,l,r,x,y,L;
while(q--)
{
cin>>op;
if(op==1)
{
cin>>l>>r;
add(1,l,r,1,n);
}
else
{
cin>>x>>y>>L;
if(x>y)swap(x,y);
ll res1=cal(1,x,x+L-1,1,n),res2=cal(1,y,y+L-1,1,n);
if(res1*p[y-x]%mod==res2)
cout<<"yes\n";
else
cout<<"no\n";
}
}
return 0;
}