题目链接

解题思路:

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

Caesar Cipher(线段树维护哈希)相关推荐

  1. 2020CCPC(威海) - Caesar Cipher(线段树+哈希)

    题目大意:给出一个长度为 n 的序列,接下来有 m 次操作,每次操作分为下列两种类型: 1 l r:区间 [ l , r ] 内的所有数都加 1 并对 65536 取模,也就是 i ∈ [ l , r ...

  2. BZOJ 2124 等差子序列 线段树维护哈希

    $ \Rightarrow $ 戳我进BZOJ原题 等差子序列 Time Limit: 3 Sec $ \quad $ Memory Limit: 259 MB Description 给一个 $ 1 ...

  3. [动态dp]线段树维护转移矩阵

    背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区 ...

  4. Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)

    题意: 操作1:把x位置的数字修改成y. 操作2:查询[l,r]之间不下降序列的个数. 题解: 线段树维护区间和问题 (这是套路,想不到只能说做题少别打我) . 用五个变量进行维护. sum区间总个数 ...

  5. [SDOI2011]染色 (线段树维护子段问题+树剖)

    题意: 给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种: 1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c. 2.询问节点 a 到节点 b 的路径上的颜色段 ...

  6. Can you answer these queries III (线段树维护最大子段和)

    题意: 求一个区间的最大连续和. 0:表示把A[x]改成y 1:表示求[x,y]这个区间的最大连续和. 题解: 线段树维护四个变量. 倒着讲,先来看如何维护这四个变量. summax代表这个区间连续最 ...

  7. 线段树 ---- D. Power Tree(离线dfs序+线段树维护树上多条路径和的技巧)

    题目链接 题目大意: 一开始给你只有一个点111的树,有qqq次询问.每次询问有两种操作 1pv1\;p\;v1pv 就是把最小的没加入的点,加入这个树,它的父亲是ppp,权值是vvv 2u2\;u2 ...

  8. 【uoj#164】[清华集训2015]V 线段树维护历史最值

    题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ : $2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ , ...

  9. Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake 线段树维护dp

    D. Babaei and Birthday Cake 题目连接: http://www.codeforces.com/contest/629/problem/D Description As you ...

最新文章

  1. python 英语词频统计软件_Python数据挖掘——文本分析
  2. java将一个整数反转输出,输入一个整数,实现反转输出,如输入123,输出321。...
  3. Java笔记3:Eclipse添加jar包
  4. css之max-width属性
  5. linux下 卸载qt_Windows 下 Qt creator安装和使用
  6. android 学习资料整理
  7. 按指定字符分割字符串
  8. 数字图像处理第五章——图像复原与重建
  9. MPC控制笔记(一)
  10. php 统计uv,简单网站统计功能的实现 PV IP 真实访客数(UV) | 学步园
  11. 固态硬盘的计算机需要进行磁盘碎片整理吗,浅析为什么固态硬盘不需要磁盘碎片整理...
  12. 在美团投放广告的优势、展现形式介绍!
  13. 红黑树(Red-Black Tree,RBT)
  14. 寻仙手游服务器无响应,寻仙手游进不去解决方法 寻仙手游怎么玩不了
  15. 与构架有关的几个基本概念
  16. 首席新媒体运营黎想教程:社群搭建及运营实操攻略
  17. python用bbp公式求圆周率_神奇的BBP公式,可独立计算圆周率任何一位数字,曾震惊数学界!...
  18. Windows Vista中强大的数码相片处理功能(转)
  19. Unity-编辑器扩展(Editor)
  20. 建模中的定量预测拟合方法

热门文章

  1. struts使用下拉列表框
  2. npm install 报错没有匹配版本:No matching version found for
  3. char* char[] string
  4. 未在服务器上找到sql安装程序文件,MS SQL Server 2000/以前的某个程序安装已在安装计算机上创建挂起的文件操作。...
  5. 【uni-app】Flex布局
  6. 第2章 Maven的安装与配置
  7. 利用决策树学习基金持仓并识别公司风格类型
  8. 将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。输出逆序后数组的整数,每两个整数之间用空格分隔。
  9. 微信hook——登录界面的账号密码
  10. Python-Level5-day10am:视频基本处理,图像处理综合案例