字符串哈希&线段树维护字符串哈希
本文哈希数组均为 1-index,原始字符串均为 0-index。
哈希值类
typedef unsigned long long ull;
ull bs=13131,bspw[MAXN+5];
inline void init_bspw(){
bspw[0]=1;
for(int i=1;i<=MAXN;i++)
bspw[i]=bspw[i-1]*bs;
}
struct HashNode{
ull val;
int len;
HashNode(){}
HashNode(ull a,int b):val(a),len(b){}
};
inline HashNode operator + (const HashNode& a,const HashNode& b){
HashNode res;
res.val=a.val*bspw[b.len]+b.val;
res.len=a.len+b.len;
return res;
}
inline HashNode operator - (const HashNode& a,const HashNode& b){//b is prefix of a
HashNode res;
res.val=a.val-b.val*bspw[a.len-b.len];
res.len=a.len-b.len;
return res;
}
inline bool operator == (const HashNode& a,const HashNode& b){
return (a.len==b.len) && (a.val==b.val);
}
静态字符串哈希
class HashString{
private:
HashNode hs[MAXN+5];
public:
inline void build(const string& str){
int len=str.size();
hs[0]=HashNode(0,0);
for(int i=1;i<=len;i++)
hs[i]=HashNode(str[i-1]-'a'+1,1);
for(int i=1;i<=len;i++)
hs[i]=hs[i-1]+hs[i];
}
inline HashNode query(const int& l,const int& r) const{
return hs[r]-hs[l-1];
}
};
双哈希
typedef unsigned long long ull;
const int MAXN=1500,MAXBSTP=2;
ull bs[MAXBSTP]={131,13131},bspw[MAXBSTP][MAXN+5];
inline void init_bspw(int bstp){
bspw[bstp][0]=1;
for(int i=1;i<=MAXN;i++)
bspw[bstp][i]=bspw[bstp][i-1]*bs[bstp];
}
struct HashNode{
ull val;
int len;
HashNode(){}
HashNode(ull a,int b):val(a),len(b){}
};
inline bool operator == (const HashNode& a,const HashNode& b){
return (a.len==b.len) && (a.val==b.val);
}
class HashString{
private:
int bstp;
HashNode hs[MAXN+5];
inline HashNode plus(const HashNode& a,const HashNode& b){
HashNode res;
res.val=a.val*bspw[bstp][b.len]+b.val;
res.len=a.len+b.len;
return res;
}
inline HashNode minusprefix(const HashNode& a,const HashNode& b){//b is prefix of a
HashNode res;
res.val=a.val-b.val*bspw[bstp][a.len-b.len];
res.len=a.len-b.len;
return res;
}
public:
HashString():bstp(0){}
HashString(int a):bstp(a){}
inline void setbase(int a){
bstp=a;
}
inline void build(const string& str){
int len=str.size();
hs[0]=HashNode(0,0);
for(int i=1;i<=len;i++)
hs[i]=HashNode(str[i-1]-'a'+1,1);
for(int i=1;i<=len;i++)
hs[i]=plus(hs[i-1],hs[i]);
}
inline HashNode query(const int& l,const int& r){
return minusprefix(hs[r],hs[l-1]);
}
};
动态字符串哈希(线段树维护哈希)
\(O(\log n)\) 单点修改,\(O(\log n)\) 区间查询。
通常不会有区间直接修改的需求,因为这样光输入就超时了。
#define getmid int mid=(l+r)/2
#define lch (pos<<1)
#define rch (pos<<1|1)
class HashSegTree{
private:
HashNode t[(MAXN<<2)+5];
inline void pushup(int pos){
t[pos]=t[lch]+t[rch];
}
public:
void build(int pos,int l,int r,const string& str){
if(l==r){
t[pos]=HashNode(str[l-1]-'a'+1,1);
return;
}
getmid;
build(lch,l,mid,str);
build(rch,mid+1,r,str);
pushup(pos);
}
void update(int pos,int l,int r,int aim,char ch){
if(l==r){
t[pos]=HashNode(ch-'a'+1,1);
return;
}
getmid;
if(aim<=mid) update(lch,l,mid,aim,ch);
else update(rch,mid+1,r,aim,ch);
pushup(pos);
}
HashNode query(int pos,int l,int r,int ll,int rr){
if(ll<=l && r<=rr){
return t[pos];
}
getmid;
HashNode res(0,0);
if(ll<=mid) res=res+query(lch,l,mid,ll,rr);
if(mid<rr) res=res+query(rch,mid+1,r,ll,rr);
return res;
}
};
线段树维护正反串哈希
仍然是 \(O(\log n)\) 单点修改,\(O(\log n)\) 区间查询。
通常用于查询字符串的某个子串是不是回文串。
#include<bits/stdc++.h>
#define getmid int mid=(l+r)/2
#define lch (pos<<1)
#define rch (pos<<1|1)
using namespace std;
typedef unsigned long long ull;
const int MAXN=1e6;
ull bs=13131,bspw[MAXN+5];
struct TwinHashNode{
ull fwd,bwd;
int len;
TwinHashNode(){}
TwinHashNode(ull a,ull b,int c):fwd(a),bwd(b),len(c){}
};
inline TwinHashNode operator + (const TwinHashNode& a,const TwinHashNode& b){
TwinHashNode res;
res.fwd=a.fwd*bspw[b.len]+b.fwd;
res.bwd=b.bwd*bspw[a.len]+a.bwd;
res.len=a.len+b.len;
return res;
}
class HashSegTree{
private:
TwinHashNode t[(MAXN<<2)+5];
inline void pushup(int pos){
t[pos]=t[lch]+t[rch];
}
public:
void build(int pos,int l,int r,const string& str){
if(l==r){
t[pos]=TwinHashNode(str[l-1]-'a'+1,str[l-1]-'a'+1,1);
return;
}
getmid;
build(lch,l,mid,str);
build(rch,mid+1,r,str);
pushup(pos);
}
void update(int pos,int l,int r,int aim,char ch){
if(l==r){
t[pos]=TwinHashNode(ch-'a'+1,ch-'a'+1,1);
return;
}
getmid;
if(aim<=mid) update(lch,l,mid,aim,ch);
else update(rch,mid+1,r,aim,ch);
pushup(pos);
}
TwinHashNode query(int pos,int l,int r,int ll,int rr){
if(ll<=l && r<=rr){
return t[pos];
}
getmid;
TwinHashNode res(0,0,0);
if(ll<=mid) res=res+query(lch,l,mid,ll,rr);
if(mid<rr) res=res+query(rch,mid+1,r,ll,rr);
return res;
}
}text;
int n,q;
string str;
int main(){
ios::sync_with_stdio(false);
cin>>n>>q>>str;
n=str.size();
bspw[0]=1;
for(int i=1;i<=n;i++)
bspw[i]=bspw[i-1]*bs;
text.build(1,1,n,str);
int opt,l,r,x;
char c;
while(q--){
cin>>opt;
if(opt==1){
cin>>x>>c;
text.update(1,1,n,x,c);
}
else{
cin>>l>>r;
auto res=text.query(1,1,n,l,r);
cout<<(res.fwd==res.bwd?"Yes":"No")<<endl;
}
}
return 0;
}