Caesar Cipher(线段树维护哈希)

18 篇文章 0 订阅

题目链接

解题思路:

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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要用bug来打败bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值