首页 > 其他分享 >字符串哈希&线段树维护字符串哈希

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

时间:2024-09-15 08:52:09浏览次数:8  
标签:log int 线段 哈希 字符串 bspw define

本文哈希数组均为 1-index,原始字符串均为 0-index。

哈希值类

typedef unsigned long long ull;
ull bs=13131,bspw[MAXN];

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

动态字符串哈希(线段树维护字符串哈希)

\(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];
    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+5;
ull bs=13131,bspw[MAXN];

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

标签:log,int,线段,哈希,字符串,bspw,define
From: https://www.cnblogs.com/SkyNet-PKN/p/18414948

相关文章

  • 字符串处理
    概念理解c风格字符串字符数组大小比字符串多一个chars[6]={'H','e','l','l','o','\0'};chars[]="Hello";用法1.存储方式及赋值'\0'占用存储空间,不计入长度作为变量使用时,不可s="hellow"s1=s2只可以逐个字符赋值sscanf(s,&......
  • 字符串处理工具类
    字符串处理工具类importjava.util.Arrays;publicclassStringUtils{/***将字符串反转*@paramstr要反转的字符串*@return反转后的字符串*/publicstaticStringreverseString(Stringstr){returnnewStringBuilder(str......
  • 哈希表简单介绍
    概念在顺序结构以及平衡树中,元素关键字与他们存储的位置并没有直接的映射关系,从而会影响查找关键字的效率,顺序结构中查找关键字的时间复杂度为O(N),平衡树查找关键字的时间复杂度为O(log2^N)。最理想的搜索方法——只搜索一次就能找到关键字。如果有一种数据结构,能够使得关键字根......
  • 【YashanDB知识库】yasql对字符串中分号的判定
    本文转载自YashanDB官网,具体内容请见https://www.yashandb.com/newsinfo/7352673.html?templateId=1718516问题现象这个问题发生在从pg向崖山进行数据迁移的过程中,通过pg\_dump将数据导出到文件后进行执行,第一条语句执行报错,在pg上执行是不会报错的,在崖山和oracle上执行均报错。与......
  • LeetCode 2390. 从字符串中移除星号(字符串、栈)
    题目:2390.从字符串中移除星号思路:使用栈就可以,这里string也可以实现栈的效果classSolution{public:stringremoveStars(strings){stringe="";for(autox:s){if(x=='*')e.pop_back();elsee.push_back(x);......
  • 2390. 从字符串中移除星号
    给你一个包含若干星号*的字符串s。在一步操作中,你可以:选中s中的一个星号。移除星号左侧最近的那个非星号字符,并移除该星号自身。返回移除所有星号之后的字符串。注意:生成的输入保证总是可以执行题面中描述的操作。可以证明结果字符串是唯一的。示例1:输入:s=......
  • 438. 找到字符串中所有字母异位词
    题目链接438.找到字符串中所有字母异位词思路滑动窗口题解链接官方题解关键点顺序比较;判断的状态量可以依此变更时应当使用“滑动窗口”的方式进行更新时间复杂度\(O(m+(n-m)\times\sum)\)空间复杂度\(O(\sum)\)代码实现:classSolution:de......
  • 【数据结构】字符串与JSON字符串、JSON字符串及相应数据结构(如对象与数组)之间的相互转
    前言:下面打印日志用的是FastJSON依赖库中的 @Log4j2。依赖:<!--AlibabaFastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.80</version></dependency>目录普通字......
  • Hash Table 哈希表工作原理介绍及C/C++/Python实现
    HashTable哈希表工作原理介绍及C/C++/Python实现哈希表(HashTable),也称为散列表,是一种通过哈希函数将键(Key)映射到表中一个位置以便快速访问记录的数据结构。它提供了非常高效的数据检索、插入和删除操作。哈希表的基本原理是使用一个哈希函数将输入(通常是字符串)转换为一个......
  • 线段树与离散化技巧 Mayor's posters——poj 2528
    问题描述:有一堵海报墙,从左到右一共有10000000个小块,墙上贴了许多海报,每张海报的高度与墙的高度相同,宽度不同,新帖的海报会将原有的海报覆盖,问当所有人把海报贴完是,墙上可以看到几张海报输入:第一行输入一个整数c表示测试数,每个测试第一行输入一个整数n(1<=N<=10000),代表张贴海报数......