字符串哈希&线段树维护字符串哈希

本文哈希数组均为 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;
}
posted @ 2024-09-15 08:31  MessageBoxA  阅读(82)  评论(0编辑  收藏  举报